Merge branch 'stable-3.1' into stable-3.2

* stable-3.1:
  Plugin reports wrong number of failures

Change-Id: I79588326d2ae104bce124e8f1f0d4cf75f54d846
diff --git a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckMetrics.java b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckMetrics.java
index cea2530..1f88020 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckMetrics.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckMetrics.java
@@ -14,84 +14,29 @@
 
 package com.googlesource.gerrit.plugins.healthcheck;
 
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.Sets;
-import com.google.gerrit.extensions.events.LifecycleListener;
-import com.google.gerrit.extensions.registration.DynamicSet;
-import com.google.gerrit.extensions.registration.RegistrationHandle;
-import com.google.gerrit.metrics.CallbackMetric0;
 import com.google.gerrit.metrics.Counter0;
 import com.google.gerrit.metrics.Description;
 import com.google.gerrit.metrics.MetricMaker;
+import com.google.gerrit.metrics.Timer0;
 import com.google.inject.Inject;
-import com.google.inject.Singleton;
-import com.googlesource.gerrit.plugins.healthcheck.check.GlobalHealthCheck;
-import com.googlesource.gerrit.plugins.healthcheck.check.HealthCheck;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
+import com.google.inject.assistedinject.Assisted;
 
-@Singleton
-public class HealthCheckMetrics implements LifecycleListener {
+public class HealthCheckMetrics {
 
-  private final DynamicSet<HealthCheck> healthChecks;
+  public interface Factory {
+    HealthCheckMetrics create(String name);
+  }
+
   private final MetricMaker metricMaker;
-  private final Set<RegistrationHandle> registeredMetrics;
-  private final Set<Runnable> triggers;
-  private final GlobalHealthCheck globalHealthCheck;
+  private final String name;
 
   @Inject
-  public HealthCheckMetrics(
-      DynamicSet<HealthCheck> healthChecks,
-      GlobalHealthCheck globalHealthCheck,
-      MetricMaker metricMaker) {
-    this.healthChecks = healthChecks;
+  public HealthCheckMetrics(MetricMaker metricMaker, @Assisted String name) {
     this.metricMaker = metricMaker;
-    this.registeredMetrics = Collections.synchronizedSet(new HashSet<>());
-    this.triggers = Collections.synchronizedSet(new HashSet<>());
-    this.globalHealthCheck = globalHealthCheck;
+    this.name = name;
   }
 
-  @Override
-  public void start() {
-
-    Set<HealthCheck> allChecks = Sets.newHashSet(healthChecks);
-    allChecks.add(globalHealthCheck);
-
-    for (HealthCheck healthCheck : allChecks) {
-      String name = healthCheck.name();
-
-      Counter0 failureMetric = getFailureMetric(name);
-      CallbackMetric0<Long> latencyMetric = getLatencyMetric(name);
-      Runnable metricCallBack = getCallbackMetric(healthCheck, failureMetric, latencyMetric);
-
-      registeredMetrics.add(failureMetric);
-      registeredMetrics.add(metricMaker.newTrigger(latencyMetric, metricCallBack));
-      triggers.add(metricCallBack);
-    }
-  }
-
-  private Runnable getCallbackMetric(
-      HealthCheck healthCheck, Counter0 failureMetric, CallbackMetric0<Long> latencyMetric) {
-    return () -> {
-      HealthCheck.StatusSummary status = healthCheck.getLatestStatus();
-      latencyMetric.set(healthCheck.getLatestStatus().elapsed);
-      if (status.isFailure()) {
-        failureMetric.increment();
-      }
-    };
-  }
-
-  private CallbackMetric0<Long> getLatencyMetric(String name) {
-    return metricMaker.newCallbackMetric(
-        String.format("%s/latest_latency", name),
-        Long.class,
-        new Description(String.format("%s health check latency execution (ms)", name))
-            .setGauge()
-            .setUnit(Description.Units.MILLISECONDS));
-  }
-
-  private Counter0 getFailureMetric(String name) {
+  public Counter0 getFailureCounterMetric() {
     return metricMaker.newCounter(
         String.format("%s/failure", name),
         new Description(String.format("%s healthcheck failures count", name))
@@ -100,15 +45,11 @@
             .setUnit("failures"));
   }
 
-  @Override
-  public void stop() {
-    for (RegistrationHandle handle : registeredMetrics) {
-      handle.remove();
-    }
-  }
-
-  @VisibleForTesting
-  public void triggerAll() {
-    triggers.forEach(Runnable::run);
+  public Timer0 getLatencyMetric() {
+    return metricMaker.newTimer(
+        String.format("%s/latest_latency", name),
+        new Description(String.format("%s health check latency execution (ms)", name))
+            .setCumulative()
+            .setUnit(Description.Units.MILLISECONDS));
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckSubsystemsModule.java b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckSubsystemsModule.java
index 6ff3d04..304a40c 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckSubsystemsModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckSubsystemsModule.java
@@ -14,9 +14,8 @@
 
 package com.googlesource.gerrit.plugins.healthcheck;
 
-import com.google.gerrit.extensions.events.LifecycleListener;
+import com.google.gerrit.extensions.config.FactoryModule;
 import com.google.gerrit.extensions.registration.DynamicSet;
-import com.google.inject.AbstractModule;
 import com.googlesource.gerrit.plugins.healthcheck.check.ActiveWorkersCheck;
 import com.googlesource.gerrit.plugins.healthcheck.check.AuthHealthCheck;
 import com.googlesource.gerrit.plugins.healthcheck.check.DeadlockCheck;
@@ -25,7 +24,7 @@
 import com.googlesource.gerrit.plugins.healthcheck.check.ProjectsListHealthCheck;
 import com.googlesource.gerrit.plugins.healthcheck.check.QueryChangesHealthCheck;
 
-public class HealthCheckSubsystemsModule extends AbstractModule {
+public class HealthCheckSubsystemsModule extends FactoryModule {
 
   @Override
   protected void configure() {
@@ -35,7 +34,8 @@
     bindChecker(AuthHealthCheck.class);
     bindChecker(ActiveWorkersCheck.class);
     bindChecker(DeadlockCheck.class);
-    bind(LifecycleListener.class).to(HealthCheckMetrics.class);
+
+    factory(HealthCheckMetrics.Factory.class);
   }
 
   private void bindChecker(Class<? extends HealthCheck> healthCheckClass) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/AbstractHealthCheck.java b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/AbstractHealthCheck.java
index d0181ab..9e4544a 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/AbstractHealthCheck.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/AbstractHealthCheck.java
@@ -16,7 +16,10 @@
 
 import com.google.common.util.concurrent.ListenableFuture;
 import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.gerrit.metrics.Counter0;
+import com.google.gerrit.metrics.Timer0;
 import com.googlesource.gerrit.plugins.healthcheck.HealthCheckConfig;
+import com.googlesource.gerrit.plugins.healthcheck.HealthCheckMetrics;
 import java.util.Collections;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
@@ -32,13 +35,23 @@
   protected volatile StatusSummary latestStatus;
   protected HealthCheckConfig config;
 
+  protected final Counter0 failureCounterMetric;
+  protected final Timer0 latencyMetric;
+
   protected AbstractHealthCheck(
-      ListeningExecutorService executor, HealthCheckConfig config, String name) {
+      ListeningExecutorService executor,
+      HealthCheckConfig config,
+      String name,
+      HealthCheckMetrics.Factory healthCheckMetricsFactory) {
     this.executor = executor;
     this.name = name;
     this.timeout = config.getTimeout(name);
     this.config = config;
     this.latestStatus = StatusSummary.INITIAL_STATUS;
+
+    HealthCheckMetrics healthCheckMetrics = healthCheckMetricsFactory.create(name);
+    this.failureCounterMetric = healthCheckMetrics.getFailureCounterMetric();
+    this.latencyMetric = healthCheckMetrics.getLatencyMetric();
   }
 
   @Override
@@ -61,30 +74,32 @@
                 log.warn("Check {} failed", name, e);
                 healthy = Result.FAILED;
               }
-              return new StatusSummary(
-                  healthy, ts, System.currentTimeMillis() - ts, Collections.emptyMap());
+              Long elapsed = System.currentTimeMillis() - ts;
+              StatusSummary statusSummary =
+                  new StatusSummary(healthy, ts, elapsed, Collections.emptyMap());
+              if (statusSummary.isFailure()) {
+                failureCounterMetric.increment();
+              }
+              latencyMetric.record(elapsed, TimeUnit.MILLISECONDS);
+              return statusSummary;
             });
     try {
       checkStatusSummary = resultFuture.get(timeout, TimeUnit.MILLISECONDS);
     } catch (TimeoutException e) {
       log.warn("Check {} timed out", name, e);
-      checkStatusSummary =
-          new StatusSummary(
-              Result.TIMEOUT, ts, System.currentTimeMillis() - ts, Collections.emptyMap());
+      Long elapsed = System.currentTimeMillis() - ts;
+      checkStatusSummary = new StatusSummary(Result.TIMEOUT, ts, elapsed, Collections.emptyMap());
+      failureCounterMetric.increment();
+      latencyMetric.record(elapsed, TimeUnit.MILLISECONDS);
     } catch (InterruptedException | ExecutionException e) {
       log.warn("Check {} failed while waiting for its future result", name, e);
-      checkStatusSummary =
-          new StatusSummary(
-              Result.FAILED, ts, System.currentTimeMillis() - ts, Collections.emptyMap());
+      Long elapsed = System.currentTimeMillis() - ts;
+      checkStatusSummary = new StatusSummary(Result.FAILED, ts, elapsed, Collections.emptyMap());
+      failureCounterMetric.increment();
+      latencyMetric.record(elapsed, TimeUnit.MILLISECONDS);
     }
-    latestStatus = checkStatusSummary.shallowCopy();
     return checkStatusSummary;
   }
 
   protected abstract Result doCheck() throws Exception;
-
-  @Override
-  public StatusSummary getLatestStatus() {
-    return latestStatus;
-  }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/ActiveWorkersCheck.java b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/ActiveWorkersCheck.java
index f3afc99..dcf2f0e 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/ActiveWorkersCheck.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/ActiveWorkersCheck.java
@@ -22,6 +22,7 @@
 import com.google.gerrit.server.config.ThreadSettingsConfig;
 import com.google.inject.Inject;
 import com.googlesource.gerrit.plugins.healthcheck.HealthCheckConfig;
+import com.googlesource.gerrit.plugins.healthcheck.HealthCheckMetrics;
 import java.util.Optional;
 import org.eclipse.jgit.lib.Config;
 
@@ -33,6 +34,7 @@
   private Integer threshold;
   private Integer interactiveThreadsMaxPoolSize;
   private MetricRegistry metricRegistry;
+  private HealthCheckMetrics.Factory healthCheckMetricsFactory;
 
   @Inject
   public ActiveWorkersCheck(
@@ -40,8 +42,9 @@
       ListeningExecutorService executor,
       HealthCheckConfig healthCheckConfig,
       ThreadSettingsConfig threadSettingsConfig,
-      MetricRegistry metricRegistry) {
-    super(executor, healthCheckConfig, ACTIVEWORKERS);
+      MetricRegistry metricRegistry,
+      HealthCheckMetrics.Factory healthCheckMetricsFactory) {
+    super(executor, healthCheckConfig, ACTIVEWORKERS, healthCheckMetricsFactory);
     this.threshold = healthCheckConfig.getActiveWorkersThreshold(ACTIVEWORKERS);
     this.metricRegistry = metricRegistry;
     this.interactiveThreadsMaxPoolSize =
diff --git a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/AuthHealthCheck.java b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/AuthHealthCheck.java
index f00b155..cd0274d 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/AuthHealthCheck.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/AuthHealthCheck.java
@@ -24,6 +24,7 @@
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 import com.googlesource.gerrit.plugins.healthcheck.HealthCheckConfig;
+import com.googlesource.gerrit.plugins.healthcheck.HealthCheckMetrics;
 import java.util.Optional;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -35,14 +36,16 @@
   private final AccountCache byIdCache;
   private final String username;
   private final String password;
+  private HealthCheckMetrics.Factory healthCheckMetricsFactory;
 
   @Inject
   public AuthHealthCheck(
       ListeningExecutorService executor,
       HealthCheckConfig config,
       Realm realm,
-      AccountCache byIdCache) {
-    super(executor, config, AUTH);
+      AccountCache byIdCache,
+      HealthCheckMetrics.Factory healthCheckMetricsFactory) {
+    super(executor, config, AUTH, healthCheckMetricsFactory);
 
     this.realm = realm;
     this.byIdCache = byIdCache;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/DeadlockCheck.java b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/DeadlockCheck.java
index db5e83a..a368246 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/DeadlockCheck.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/DeadlockCheck.java
@@ -20,6 +20,7 @@
 import com.google.common.util.concurrent.ListeningExecutorService;
 import com.google.inject.Inject;
 import com.googlesource.gerrit.plugins.healthcheck.HealthCheckConfig;
+import com.googlesource.gerrit.plugins.healthcheck.HealthCheckMetrics;
 import java.util.Optional;
 
 public class DeadlockCheck extends AbstractHealthCheck {
@@ -28,13 +29,15 @@
       "proc/jvm/thread/num_deadlocked_threads";
 
   private final MetricRegistry metricRegistry;
+  private HealthCheckMetrics.Factory healthCheckMetricsFactory;
 
   @Inject
   public DeadlockCheck(
       ListeningExecutorService executor,
       HealthCheckConfig healthCheckConfig,
-      MetricRegistry metricRegistry) {
-    super(executor, healthCheckConfig, DEADLOCK);
+      MetricRegistry metricRegistry,
+      HealthCheckMetrics.Factory healthCheckMetricsFactory) {
+    super(executor, healthCheckConfig, DEADLOCK, healthCheckMetricsFactory);
     this.metricRegistry = metricRegistry;
   }
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/GlobalHealthCheck.java b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/GlobalHealthCheck.java
index c464a9e..b004eaa 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/GlobalHealthCheck.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/GlobalHealthCheck.java
@@ -14,22 +14,32 @@
 
 package com.googlesource.gerrit.plugins.healthcheck.check;
 
+import static com.googlesource.gerrit.plugins.healthcheck.check.HealthCheckNames.GLOBAL;
+
+import com.google.common.util.concurrent.ListeningExecutorService;
 import com.google.gerrit.extensions.registration.DynamicSet;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
+import com.googlesource.gerrit.plugins.healthcheck.HealthCheckConfig;
+import com.googlesource.gerrit.plugins.healthcheck.HealthCheckMetrics;
 import java.util.Arrays;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 import java.util.stream.StreamSupport;
 
 @Singleton
-public class GlobalHealthCheck implements HealthCheck {
+public class GlobalHealthCheck extends AbstractHealthCheck {
 
   private final DynamicSet<HealthCheck> healthChecks;
-  private volatile StatusSummary latestStatus = StatusSummary.INITIAL_STATUS;
 
   @Inject
-  public GlobalHealthCheck(DynamicSet<HealthCheck> healthChecks) {
+  public GlobalHealthCheck(
+      DynamicSet<HealthCheck> healthChecks,
+      ListeningExecutorService executor,
+      HealthCheckConfig healthCheckConfig,
+      HealthCheckMetrics.Factory healthCheckMetricsFactory) {
+    super(executor, healthCheckConfig, GLOBAL, healthCheckMetricsFactory);
     this.healthChecks = healthChecks;
   }
 
@@ -48,10 +58,18 @@
             ts,
             elapsed,
             checkToResults);
-    latestStatus = globalStatus.shallowCopy();
+    if (globalStatus.isFailure()) {
+      failureCounterMetric.increment();
+    }
+    latencyMetric.record(elapsed, TimeUnit.MILLISECONDS);
     return globalStatus;
   }
 
+  @Override
+  protected Result doCheck() {
+    return run().result;
+  }
+
   public static boolean hasAnyFailureOnResults(Map<String, Object> results) {
     return results.values().stream()
         .filter(
@@ -61,14 +79,4 @@
         .findAny()
         .isPresent();
   }
-
-  @Override
-  public String name() {
-    return "global";
-  }
-
-  @Override
-  public StatusSummary getLatestStatus() {
-    return latestStatus;
-  }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/HealthCheck.java b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/HealthCheck.java
index 46acdde..7c4f8a1 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/HealthCheck.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/HealthCheck.java
@@ -55,15 +55,9 @@
     public Boolean isFailure() {
       return failingResults.contains(this.result);
     }
-
-    public StatusSummary shallowCopy() {
-      return new StatusSummary(result, ts, elapsed, Collections.emptyMap());
-    }
   }
 
   StatusSummary run();
 
   String name();
-
-  StatusSummary getLatestStatus();
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/HealthCheckNames.java b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/HealthCheckNames.java
index ac4ba51..97e06d0 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/HealthCheckNames.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/HealthCheckNames.java
@@ -21,4 +21,5 @@
   String AUTH = "auth";
   String ACTIVEWORKERS = "activeworkers";
   String DEADLOCK = "deadlock";
+  String GLOBAL = "global";
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/JGitHealthCheck.java b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/JGitHealthCheck.java
index 9c6930f..d107588 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/JGitHealthCheck.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/JGitHealthCheck.java
@@ -22,6 +22,7 @@
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 import com.googlesource.gerrit.plugins.healthcheck.HealthCheckConfig;
+import com.googlesource.gerrit.plugins.healthcheck.HealthCheckMetrics;
 import java.util.Set;
 import org.eclipse.jgit.lib.Repository;
 
@@ -30,13 +31,15 @@
   private final GitRepositoryManager repositoryManager;
   private final Set<Project.NameKey> repositoryNameKeys;
 
+  private HealthCheckMetrics.Factory healthCheckMetricsFactory;
+
   @Inject
   public JGitHealthCheck(
       ListeningExecutorService executor,
       HealthCheckConfig config,
-      GitRepositoryManager repositoryManager) {
-    super(executor, config, JGIT);
-
+      GitRepositoryManager repositoryManager,
+      HealthCheckMetrics.Factory healthCheckMetricsFactory) {
+    super(executor, config, JGIT, healthCheckMetricsFactory);
     this.repositoryManager = repositoryManager;
     this.repositoryNameKeys = config.getJGITRepositories(JGIT);
   }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/ProjectsListHealthCheck.java b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/ProjectsListHealthCheck.java
index 4da142d..9850a10 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/ProjectsListHealthCheck.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/ProjectsListHealthCheck.java
@@ -22,6 +22,7 @@
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 import com.googlesource.gerrit.plugins.healthcheck.HealthCheckConfig;
+import com.googlesource.gerrit.plugins.healthcheck.HealthCheckMetrics;
 import java.util.SortedMap;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -32,10 +33,15 @@
   private static final int PROJECTS_LIST_LIMIT = 100;
   private final ListProjects listProjects;
 
+  private HealthCheckMetrics.Factory healthCheckMetricsFactory;
+
   @Inject
   public ProjectsListHealthCheck(
-      ListeningExecutorService executor, HealthCheckConfig config, ListProjects listProjects) {
-    super(executor, config, PROJECTSLIST);
+      ListeningExecutorService executor,
+      HealthCheckConfig config,
+      ListProjects listProjects,
+      HealthCheckMetrics.Factory healthCheckMetricsFactory) {
+    super(executor, config, PROJECTSLIST, healthCheckMetricsFactory);
 
     this.listProjects = listProjects;
   }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/QueryChangesHealthCheck.java b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/QueryChangesHealthCheck.java
index 5ccaf9b..9b6825f 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/QueryChangesHealthCheck.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/check/QueryChangesHealthCheck.java
@@ -24,6 +24,7 @@
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
 import com.googlesource.gerrit.plugins.healthcheck.HealthCheckConfig;
+import com.googlesource.gerrit.plugins.healthcheck.HealthCheckMetrics;
 import java.util.List;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -36,13 +37,16 @@
   private final int limit;
   private final OneOffRequestContext oneOffCtx;
 
+  private HealthCheckMetrics.Factory healthCheckMetricsFactory;
+
   @Inject
   public QueryChangesHealthCheck(
       ListeningExecutorService executor,
       HealthCheckConfig config,
       Provider<QueryChanges> queryChangesProvider,
-      OneOffRequestContext oneOffCtx) {
-    super(executor, config, QUERYCHANGES);
+      OneOffRequestContext oneOffCtx,
+      HealthCheckMetrics.Factory healthCheckMetricsFactory) {
+    super(executor, config, QUERYCHANGES, healthCheckMetricsFactory);
     this.queryChangesProvider = queryChangesProvider;
     this.config = config;
     this.limit = config.getLimit(QUERYCHANGES);
diff --git a/src/test/java/com/googlesource/gerrit/plugins/healthcheck/AbstractHealthCheckTest.java b/src/test/java/com/googlesource/gerrit/plugins/healthcheck/AbstractHealthCheckTest.java
new file mode 100644
index 0000000..f67802e
--- /dev/null
+++ b/src/test/java/com/googlesource/gerrit/plugins/healthcheck/AbstractHealthCheckTest.java
@@ -0,0 +1,195 @@
+// 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.googlesource.gerrit.plugins.healthcheck;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.google.gerrit.metrics.Counter0;
+import com.google.gerrit.metrics.Description;
+import com.google.gerrit.metrics.DisabledMetricMaker;
+import com.google.gerrit.metrics.MetricMaker;
+import com.google.gerrit.metrics.Timer0;
+import com.google.inject.Inject;
+import com.googlesource.gerrit.plugins.healthcheck.check.AbstractHealthCheck;
+import com.googlesource.gerrit.plugins.healthcheck.check.HealthCheck;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import org.junit.Before;
+import org.junit.Test;
+
+public class AbstractHealthCheckTest {
+
+  private ListeningExecutorService executor;
+  MetricMaker testMetricMaker;
+  DummyHealthCheckMetricsFactory healthCheckMetricsFactory = new DummyHealthCheckMetricsFactory();
+
+  @Before
+  public void setUp() throws Exception {
+    testMetricMaker = new TestMetricMaker();
+  }
+
+  @Test
+  public void shouldPublishAllMetricsWhenFailing() {
+    TestCheck testCheck = createFailingTestCheck();
+
+    testCheck.run();
+
+    TestMetricMaker testMetricMaker = healthCheckMetricsFactory.getMetricMaker();
+    assertThat(testMetricMaker.getFailureCount()).isEqualTo(TestMetricMaker.expectedFailureCount);
+    assertThat(testMetricMaker.getLatency()).isEqualTo(TestMetricMaker.expectedLatency);
+  }
+
+  @Test
+  public void shouldPublishAllMetricsWhenTimingOut() {
+    TestCheck testCheck = createTimingOutTestCheck();
+
+    testCheck.run();
+
+    TestMetricMaker testMetricMaker = healthCheckMetricsFactory.getMetricMaker();
+    assertThat(testMetricMaker.getFailureCount()).isEqualTo(TestMetricMaker.expectedFailureCount);
+    assertThat(testMetricMaker.getLatency()).isEqualTo(TestMetricMaker.expectedLatency);
+  }
+
+  @Test
+  public void shouldPublishOnlyLatencyMetricsWhenPassing() {
+    TestCheck testCheck = createPassingTestCheck();
+
+    testCheck.run();
+
+    TestMetricMaker testMetricMaker = healthCheckMetricsFactory.getMetricMaker();
+    assertThat(testMetricMaker.getFailureCount()).isEqualTo(0L);
+    assertThat(testMetricMaker.getLatency()).isEqualTo(TestMetricMaker.expectedLatency);
+  }
+
+  @Test
+  public void shouldPublishOnlyLatencyMetricsWhenDisabled() {
+    TestCheck testCheck = createDisabledTestCheck();
+
+    testCheck.run();
+
+    TestMetricMaker testMetricMaker = healthCheckMetricsFactory.getMetricMaker();
+    assertThat(testMetricMaker.getFailureCount()).isEqualTo(0L);
+    assertThat(testMetricMaker.getLatency()).isEqualTo(TestMetricMaker.expectedLatency);
+  }
+
+  public TestCheck createPassingTestCheck() {
+    return createTestCheckWithStatus(HealthCheck.Result.PASSED);
+  }
+
+  public TestCheck createFailingTestCheck() {
+    return createTestCheckWithStatus(HealthCheck.Result.FAILED);
+  }
+
+  public TestCheck createDisabledTestCheck() {
+    return createTestCheckWithStatus(HealthCheck.Result.DISABLED);
+  }
+
+  public TestCheck createTimingOutTestCheck() {
+    return createTestCheckWithStatus(HealthCheck.Result.TIMEOUT);
+  }
+
+  private TestCheck createTestCheckWithStatus(HealthCheck.Result result) {
+    return new TestCheck(
+        executor, HealthCheckConfig.DEFAULT_CONFIG, "testCheck", healthCheckMetricsFactory, result);
+  }
+
+  private static class TestCheck extends AbstractHealthCheck {
+    @Inject private ListeningExecutorService executor;
+    private final Result finalResult;
+    private DummyHealthCheckMetricsFactory healthCheckMetricsFactory =
+        new DummyHealthCheckMetricsFactory();
+
+    public TestCheck(
+        ListeningExecutorService executor,
+        HealthCheckConfig config,
+        String name,
+        HealthCheckMetrics.Factory healthCheckMetricsFactory,
+        Result finalResult) {
+      super(
+          MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10)),
+          config,
+          name,
+          healthCheckMetricsFactory);
+      this.finalResult = finalResult;
+    }
+
+    @Override
+    protected Result doCheck() throws Exception {
+      return finalResult;
+    }
+  }
+
+  private static class TestMetricMaker extends DisabledMetricMaker {
+    private Long failureCount = 0L;
+    private Long latency = 0L;
+    public static Long expectedFailureCount = 1L;
+    public static Long expectedLatency = 100L;
+
+    @Override
+    public Counter0 newCounter(String name, Description desc) {
+      return new Counter0() {
+
+        @Override
+        public void incrementBy(long value) {
+          failureCount += value;
+        }
+
+        @Override
+        public void increment() {
+          failureCount = expectedFailureCount;
+        }
+
+        @Override
+        public void remove() {}
+      };
+    }
+
+    @Override
+    public Timer0 newTimer(String name, Description desc) {
+      return new Timer0(name) {
+        @Override
+        protected void doRecord(long value, TimeUnit unit) {
+          latency = expectedLatency;
+        }
+
+        @Override
+        public void remove() {}
+      };
+    }
+
+    public Long getLatency() {
+      return latency;
+    }
+
+    public Long getFailureCount() {
+      return failureCount;
+    }
+  }
+
+  private static class DummyHealthCheckMetricsFactory implements HealthCheckMetrics.Factory {
+    private final TestMetricMaker metricMaker = new TestMetricMaker();
+
+    @Override
+    public HealthCheckMetrics create(String name) {
+      return new HealthCheckMetrics(metricMaker, name);
+    }
+
+    public TestMetricMaker getMetricMaker() {
+      return metricMaker;
+    }
+  }
+}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/healthcheck/ActiveWorkersCheckTest.java b/src/test/java/com/googlesource/gerrit/plugins/healthcheck/ActiveWorkersCheckTest.java
index 71bef43..df88c48 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/healthcheck/ActiveWorkersCheckTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/healthcheck/ActiveWorkersCheckTest.java
@@ -32,15 +32,7 @@
 import org.junit.Test;
 
 public class ActiveWorkersCheckTest {
-
-  @Test
-  public void shouldPassCheckWhenNoMetric() {
-
-    Injector injector = testInjector(new TestModule(new Config(), new MetricRegistry()));
-
-    ActiveWorkersCheck check = createCheck(injector);
-    assertThat(check.run().result).isEqualTo(Result.PASSED);
-  }
+  HealthCheckMetrics.Factory healthCheckMetricsFactory = new DummyHealthCheckMetricsFactory();
 
   @Test
   public void shouldPassCheckWhenNoActiveWorkers() {
@@ -139,7 +131,8 @@
         injector.getInstance(ListeningExecutorService.class),
         healtchCheckConfig,
         injector.getInstance(ThreadSettingsConfig.class),
-        injector.getInstance(MetricRegistry.class));
+        injector.getInstance(MetricRegistry.class),
+        healthCheckMetricsFactory);
   }
 
   private class TestModule extends AbstractModule {
diff --git a/src/test/java/com/googlesource/gerrit/plugins/healthcheck/DeadlockCheckTest.java b/src/test/java/com/googlesource/gerrit/plugins/healthcheck/DeadlockCheckTest.java
index d53a1d8..79a4bc4 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/healthcheck/DeadlockCheckTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/healthcheck/DeadlockCheckTest.java
@@ -32,6 +32,8 @@
 
 public class DeadlockCheckTest {
 
+  HealthCheckMetrics.Factory healthCheckMetricsFactory = new DummyHealthCheckMetricsFactory();
+
   @Test
   public void shouldPassCheckWhenNoMetric() {
 
@@ -91,7 +93,8 @@
     return new DeadlockCheck(
         injector.getInstance(ListeningExecutorService.class),
         DEFAULT_CONFIG,
-        injector.getInstance(MetricRegistry.class));
+        injector.getInstance(MetricRegistry.class),
+        healthCheckMetricsFactory);
   }
 
   private class TestModule extends AbstractModule {
diff --git a/src/test/java/com/googlesource/gerrit/plugins/healthcheck/DummyHealthCheckMetricsFactory.java b/src/test/java/com/googlesource/gerrit/plugins/healthcheck/DummyHealthCheckMetricsFactory.java
new file mode 100644
index 0000000..7523e95
--- /dev/null
+++ b/src/test/java/com/googlesource/gerrit/plugins/healthcheck/DummyHealthCheckMetricsFactory.java
@@ -0,0 +1,28 @@
+// 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.googlesource.gerrit.plugins.healthcheck;
+
+import com.google.gerrit.metrics.DisabledMetricMaker;
+import com.google.gerrit.metrics.MetricMaker;
+import org.junit.Ignore;
+
+@Ignore
+public class DummyHealthCheckMetricsFactory implements HealthCheckMetrics.Factory {
+  @Override
+  public HealthCheckMetrics create(String name) {
+    MetricMaker metricMaker = new DisabledMetricMaker();
+    return new HealthCheckMetrics(metricMaker, name);
+  }
+}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckMetricsTest.java b/src/test/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckMetricsTest.java
index 1c01950..b186658 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckMetricsTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckMetricsTest.java
@@ -16,115 +16,58 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.gerrit.extensions.events.LifecycleListener;
-import com.google.gerrit.extensions.registration.DynamicSet;
-import com.google.gerrit.metrics.CallbackMetric0;
 import com.google.gerrit.metrics.Counter0;
 import com.google.gerrit.metrics.Description;
 import com.google.gerrit.metrics.DisabledMetricMaker;
-import com.google.gerrit.metrics.MetricMaker;
-import com.google.inject.AbstractModule;
-import com.google.inject.Guice;
-import com.google.inject.Inject;
-import com.google.inject.Injector;
-import com.google.inject.Singleton;
-import com.googlesource.gerrit.plugins.healthcheck.check.AbstractHealthCheck;
-import com.googlesource.gerrit.plugins.healthcheck.check.HealthCheck;
-import com.googlesource.gerrit.plugins.healthcheck.check.HealthCheck.Result;
-import com.googlesource.gerrit.plugins.healthcheck.check.HealthCheck.StatusSummary;
-import java.util.Collections;
-import org.junit.Before;
+import com.google.gerrit.metrics.Timer0;
+import java.util.concurrent.TimeUnit;
 import org.junit.Test;
 
 public class HealthCheckMetricsTest {
 
-  @Inject private ListeningExecutorService executor;
-  private TestMetrics testMetrics = new TestMetrics();
-
-  @Before
-  public void setUp() throws Exception {
-    testMetrics.reset();
-  }
-
-  private void setWithStatusSummary(StatusSummary StatusSummary) {
-    TestHealthCheck testHealthCheck = new TestHealthCheck(executor, "test", StatusSummary);
-
-    Injector injector =
-        testInjector(
-            new AbstractModule() {
-              @Override
-              protected void configure() {
-                DynamicSet.bind(binder(), HealthCheck.class).toInstance(testHealthCheck);
-                bind(MetricMaker.class).toInstance(testMetrics);
-                bind(LifecycleListener.class).to(HealthCheckMetrics.class);
-              }
-            });
-    HealthCheckMetrics healthCheckMetrics = injector.getInstance(HealthCheckMetrics.class);
-
-    healthCheckMetrics.start();
-    testHealthCheck.run();
-    healthCheckMetrics.triggerAll();
+  @Test
+  public void shouldReturnACounterWithCorrectValues() {
+    String testMetricName = "testMetric";
+    TestMetrics testMetrics = new TestMetrics();
+    HealthCheckMetrics healthCheckMetrics = new HealthCheckMetrics(testMetrics, testMetricName);
+    healthCheckMetrics.getFailureCounterMetric();
+    assertThat(testMetrics.metricName).isEqualTo(testMetricName + "/failure");
+    assertThat(testMetrics.metricDescription.toString())
+        .isEqualTo(
+            new Description(String.format("%s healthcheck failures count", testMetricName))
+                .setCumulative()
+                .setRate()
+                .setUnit("failures")
+                .toString());
   }
 
   @Test
-  public void shouldSendCounterWhenStatusSummaryFailed() {
-    Long elapsed = 100L;
-    setWithStatusSummary(new StatusSummary(Result.FAILED, 1L, elapsed, Collections.emptyMap()));
-
-    assertThat(testMetrics.getFailures()).isEqualTo(1);
-    assertThat(testMetrics.getLatency()).isEqualTo(elapsed);
+  public void shouldReturnATimerWithCorrectValues() {
+    String testMetricName = "testMetric";
+    TestMetrics testMetrics = new TestMetrics();
+    HealthCheckMetrics healthCheckMetrics = new HealthCheckMetrics(testMetrics, testMetricName);
+    healthCheckMetrics.getLatencyMetric();
+    assertThat(testMetrics.metricName).isEqualTo(testMetricName + "/latest_latency");
+    assertThat(testMetrics.metricDescription.toString())
+        .isEqualTo(
+            new Description(String.format("%s health check latency execution (ms)", testMetricName))
+                .setCumulative()
+                .setUnit(Description.Units.MILLISECONDS)
+                .toString());
   }
 
-  @Test
-  public void shouldSendCounterWhenStatusSummaryTimeout() {
-    Long elapsed = 100L;
-    setWithStatusSummary(new StatusSummary(Result.TIMEOUT, 1L, elapsed, Collections.emptyMap()));
-
-    assertThat(testMetrics.getFailures()).isEqualTo(1);
-    assertThat(testMetrics.getLatency()).isEqualTo(elapsed);
-  }
-
-  @Test
-  public void shouldNOTSendCounterWhenStatusSummarySuccess() {
-    Long elapsed = 100L;
-    setWithStatusSummary(new StatusSummary(Result.PASSED, 1L, elapsed, Collections.emptyMap()));
-
-    assertThat(testMetrics.failures).isEqualTo(0L);
-    assertThat(testMetrics.getLatency()).isEqualTo(elapsed);
-  }
-
-  private Injector testInjector(AbstractModule testModule) {
-    return Guice.createInjector(new HealthCheckModule(), testModule);
-  }
-
-  @Singleton
   private static class TestMetrics extends DisabledMetricMaker {
-    private Long failures = 0L;
-    private Long latency = 0L;
-
-    public Long getFailures() {
-      return failures;
-    }
-
-    public Long getLatency() {
-      return latency;
-    }
-
-    public void reset() {
-      failures = 0L;
-      latency = 0L;
-    }
+    String metricName;
+    Description metricDescription;
 
     @Override
     public Counter0 newCounter(String name, Description desc) {
+      metricName = name;
+      metricDescription = desc;
       return new Counter0() {
+
         @Override
-        public void incrementBy(long value) {
-          if (!name.startsWith("global/")) {
-            failures += value;
-          }
-        }
+        public void incrementBy(long value) {}
 
         @Override
         public void remove() {}
@@ -132,38 +75,16 @@
     }
 
     @Override
-    public <V> CallbackMetric0<V> newCallbackMetric(
-        String name, Class<V> valueClass, Description desc) {
-      return new CallbackMetric0<V>() {
+    public Timer0 newTimer(String name, Description desc) {
+      metricName = name;
+      metricDescription = desc;
+      return new Timer0(name) {
         @Override
-        public void set(V value) {
-          if (!name.startsWith("global/")) {
-            latency = (Long) value;
-          }
-        }
+        protected void doRecord(long value, TimeUnit unit) {}
 
         @Override
         public void remove() {}
       };
     }
   }
-
-  private static class TestHealthCheck extends AbstractHealthCheck {
-
-    protected TestHealthCheck(
-        ListeningExecutorService executor, String name, StatusSummary returnStatusSummary) {
-      super(executor, HealthCheckConfig.DEFAULT_CONFIG, name);
-      this.latestStatus = returnStatusSummary;
-    }
-
-    @Override
-    protected Result doCheck() {
-      return latestStatus.result;
-    }
-
-    @Override
-    public StatusSummary run() {
-      return latestStatus;
-    }
-  }
 }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckStatusEndpointTest.java b/src/test/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckStatusEndpointTest.java
index 78b89e4..b2fb862 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckStatusEndpointTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckStatusEndpointTest.java
@@ -17,16 +17,17 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.googlesource.gerrit.plugins.healthcheck.HealthCheckConfig.DEFAULT_CONFIG;
 
+import com.google.common.util.concurrent.ListeningExecutorService;
 import com.google.common.util.concurrent.MoreExecutors;
 import com.google.gerrit.extensions.registration.DynamicSet;
 import com.google.gerrit.extensions.restapi.Response;
-import com.google.gerrit.metrics.DisabledMetricMaker;
-import com.google.gerrit.metrics.MetricMaker;
 import com.google.inject.AbstractModule;
 import com.google.inject.Guice;
+import com.google.inject.Inject;
 import com.google.inject.Injector;
 import com.googlesource.gerrit.plugins.healthcheck.api.HealthCheckStatusEndpoint;
 import com.googlesource.gerrit.plugins.healthcheck.check.AbstractHealthCheck;
+import com.googlesource.gerrit.plugins.healthcheck.check.GlobalHealthCheck;
 import com.googlesource.gerrit.plugins.healthcheck.check.HealthCheck;
 import java.util.concurrent.Executors;
 import javax.servlet.http.HttpServletResponse;
@@ -34,13 +35,24 @@
 
 public class HealthCheckStatusEndpointTest {
 
+  @Inject private ListeningExecutorService executor;
+  HealthCheckMetrics.Factory healthCheckMetricsFactory = new DummyHealthCheckMetricsFactory();
+
   public static class TestHealthCheck extends AbstractHealthCheck {
     private final HealthCheck.Result checkResult;
     private final long sleep;
 
     public TestHealthCheck(
-        HealthCheckConfig config, String checkName, HealthCheck.Result result, long sleep) {
-      super(MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10)), config, checkName);
+        HealthCheckConfig config,
+        String checkName,
+        HealthCheck.Result result,
+        long sleep,
+        HealthCheckMetrics.Factory healthCheckMetricsFactory) {
+      super(
+          MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10)),
+          config,
+          checkName,
+          healthCheckMetricsFactory);
       this.checkResult = result;
       this.sleep = sleep;
     }
@@ -53,11 +65,6 @@
       }
       return checkResult;
     }
-
-    @Override
-    public StatusSummary getLatestStatus() {
-      return this.latestStatus;
-    }
   }
 
   @Test
@@ -67,12 +74,22 @@
             new AbstractModule() {
               @Override
               protected void configure() {
-                DynamicSet.bind(binder(), HealthCheck.class)
-                    .toInstance(
-                        new TestHealthCheck(
-                            DEFAULT_CONFIG, "checkOk", HealthCheck.Result.PASSED, 0));
-                bind(HealthCheckConfig.class).toInstance(DEFAULT_CONFIG);
-                DynamicSet.bind(binder(), MetricMaker.class).toInstance(new DisabledMetricMaker());
+                HealthCheckConfig config =
+                    new HealthCheckConfig("[healthcheck]\n" + "timeout = 20");
+                TestHealthCheck passingHealthCheck =
+                    new TestHealthCheck(
+                        DEFAULT_CONFIG,
+                        "checkOk",
+                        HealthCheck.Result.PASSED,
+                        0,
+                        healthCheckMetricsFactory);
+                DynamicSet<HealthCheck> healthChecks = new DynamicSet<>();
+                healthChecks.add("passingHealthCheck", passingHealthCheck);
+                GlobalHealthCheck globalHealthCheck =
+                    new GlobalHealthCheck(
+                        healthChecks, executor, config, healthCheckMetricsFactory);
+                bind(GlobalHealthCheck.class).toInstance(globalHealthCheck);
+                bind(HealthCheckConfig.class).toInstance(config);
               }
             });
 
@@ -92,9 +109,19 @@
               protected void configure() {
                 HealthCheckConfig config =
                     new HealthCheckConfig("[healthcheck]\n" + "timeout = 20");
-                DynamicSet.bind(binder(), HealthCheck.class)
-                    .toInstance(
-                        new TestHealthCheck(config, "checkOk", HealthCheck.Result.PASSED, 30));
+                TestHealthCheck testHealthCheck =
+                    new TestHealthCheck(
+                        config,
+                        "checkOk",
+                        HealthCheck.Result.PASSED,
+                        30,
+                        healthCheckMetricsFactory);
+                DynamicSet<HealthCheck> healthChecks = new DynamicSet<>();
+                healthChecks.add("testHealthCheck", testHealthCheck);
+                GlobalHealthCheck globalHealthCheck =
+                    new GlobalHealthCheck(
+                        healthChecks, executor, config, healthCheckMetricsFactory);
+                bind(GlobalHealthCheck.class).toInstance(globalHealthCheck);
                 bind(HealthCheckConfig.class).toInstance(config);
               }
             });
@@ -113,14 +140,32 @@
             new AbstractModule() {
               @Override
               protected void configure() {
-                DynamicSet.bind(binder(), HealthCheck.class)
-                    .toInstance(
-                        new TestHealthCheck(
-                            DEFAULT_CONFIG, "checkOk", HealthCheck.Result.PASSED, 0));
-                DynamicSet.bind(binder(), HealthCheck.class)
-                    .toInstance(
-                        new TestHealthCheck(
-                            DEFAULT_CONFIG, "checkKo", HealthCheck.Result.FAILED, 0));
+                HealthCheckConfig config =
+                    new HealthCheckConfig("[healthcheck]\n" + "timeout = 20");
+                TestHealthCheck passingHealthCheck =
+                    new TestHealthCheck(
+                        DEFAULT_CONFIG,
+                        "checkOk",
+                        HealthCheck.Result.PASSED,
+                        0,
+                        healthCheckMetricsFactory);
+
+                TestHealthCheck failingHealthCheck =
+                    new TestHealthCheck(
+                        DEFAULT_CONFIG,
+                        "checkKo",
+                        HealthCheck.Result.FAILED,
+                        0,
+                        healthCheckMetricsFactory);
+
+                DynamicSet<HealthCheck> healthChecks = new DynamicSet<>();
+                healthChecks.add("passingHealthCheck", passingHealthCheck);
+                healthChecks.add("failingHealthCheck", failingHealthCheck);
+                GlobalHealthCheck globalHealthCheck =
+                    new GlobalHealthCheck(
+                        healthChecks, executor, config, healthCheckMetricsFactory);
+                bind(GlobalHealthCheck.class).toInstance(globalHealthCheck);
+                bind(HealthCheckConfig.class).toInstance(config);
               }
             });
 
diff --git a/src/test/java/com/googlesource/gerrit/plugins/healthcheck/JGitHealthCheckTest.java b/src/test/java/com/googlesource/gerrit/plugins/healthcheck/JGitHealthCheckTest.java
index 74956c6..3c0adae 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/healthcheck/JGitHealthCheckTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/healthcheck/JGitHealthCheckTest.java
@@ -52,6 +52,8 @@
 
   @Inject private ListeningExecutorService executor;
 
+  HealthCheckMetrics.Factory healthCheckMetricsFactory = new DummyHealthCheckMetricsFactory();
+
   @Before
   public void setupAllProjects() throws Exception {
     Guice.createInjector(new HealthCheckModule()).injectMembers(this);
@@ -68,14 +70,16 @@
   @Test
   public void shouldBeHealthyWhenJGitIsWorking() {
     JGitHealthCheck check =
-        new JGitHealthCheck(executor, DEFAULT_CONFIG, getWorkingRepositoryManager());
+        new JGitHealthCheck(
+            executor, DEFAULT_CONFIG, getWorkingRepositoryManager(), healthCheckMetricsFactory);
     assertThat(check.run().result).isEqualTo(Result.PASSED);
   }
 
   @Test
   public void shouldBeUnhealthyWhenJGitIsFailingForAllRepos() {
     JGitHealthCheck jGitHealthCheck =
-        new JGitHealthCheck(executor, DEFAULT_CONFIG, getFailingGitRepositoryManager());
+        new JGitHealthCheck(
+            executor, DEFAULT_CONFIG, getFailingGitRepositoryManager(), healthCheckMetricsFactory);
     assertThat(jGitHealthCheck.run().result).isEqualTo(Result.FAILED);
   }
 
@@ -89,7 +93,8 @@
                 + "  project = All-Users\n"
                 + "  project = Not-Existing-Repo");
     JGitHealthCheck jGitHealthCheck =
-        new JGitHealthCheck(executor, config, getWorkingRepositoryManager());
+        new JGitHealthCheck(
+            executor, config, getWorkingRepositoryManager(), healthCheckMetricsFactory);
     assertThat(jGitHealthCheck.run().result).isEqualTo(Result.FAILED);
   }
 
diff --git a/src/test/java/com/googlesource/gerrit/plugins/healthcheck/ProjectsListHealthCheckTest.java b/src/test/java/com/googlesource/gerrit/plugins/healthcheck/ProjectsListHealthCheckTest.java
index 2ab0d83..c8d25b6 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/healthcheck/ProjectsListHealthCheckTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/healthcheck/ProjectsListHealthCheckTest.java
@@ -34,6 +34,8 @@
 public class ProjectsListHealthCheckTest {
   @Inject private ListeningExecutorService executor;
 
+  HealthCheckMetrics.Factory healthCheckMetricsFactory = new DummyHealthCheckMetricsFactory();
+
   private Config gerritConfig = new Config();
 
   @Before
@@ -44,14 +46,16 @@
   @Test
   public void shouldBeHealthyWhenListProjectsWorks() {
     ProjectsListHealthCheck jGitHealthCheck =
-        new ProjectsListHealthCheck(executor, DEFAULT_CONFIG, getWorkingProjectList(0));
+        new ProjectsListHealthCheck(
+            executor, DEFAULT_CONFIG, getWorkingProjectList(0), healthCheckMetricsFactory);
     assertThat(jGitHealthCheck.run().result).isEqualTo(Result.PASSED);
   }
 
   @Test
   public void shouldBeUnhealthyWhenListProjectsIsFailing() {
     ProjectsListHealthCheck jGitHealthCheck =
-        new ProjectsListHealthCheck(executor, DEFAULT_CONFIG, getFailingProjectList());
+        new ProjectsListHealthCheck(
+            executor, DEFAULT_CONFIG, getFailingProjectList(), healthCheckMetricsFactory);
     assertThat(jGitHealthCheck.run().result).isEqualTo(Result.FAILED);
   }
 
@@ -59,7 +63,10 @@
   public void shouldBeUnhealthyWhenListProjectsIsTimingOut() {
     ProjectsListHealthCheck jGitHealthCheck =
         new ProjectsListHealthCheck(
-            executor, DEFAULT_CONFIG, getWorkingProjectList(DEFAULT_CONFIG.getTimeout() * 2));
+            executor,
+            DEFAULT_CONFIG,
+            getWorkingProjectList(DEFAULT_CONFIG.getTimeout() * 2),
+            healthCheckMetricsFactory);
     assertThat(jGitHealthCheck.run().result).isEqualTo(Result.TIMEOUT);
   }