Merge branch 'stable-3.0' into stable-3.1

* stable-3.0:
  Disable querychanges for gerrit replicas
  Normalize response payload returned by replicas
  Expose authenticated healthcheck for replicas

Change-Id: Icd33d78a8ba94c5af6a9e572eca67ea831648424
diff --git a/README.md b/README.md
index af7fc3f..8be0b33 100644
--- a/README.md
+++ b/README.md
@@ -26,8 +26,8 @@
 
 Copy the healthcheck.jar into the Gerrit's /plugins directory and wait for the plugin to be automatically loaded.
 The healthcheck plugin is compatible with both primary Gerrit setups and Gerrit replicas. The only difference to bear
-in mind is that some checks may not be successful on replicas (e.g. query changes) because the associated subsystem is
-switched off.
+in mind is that some checks will be automatically disabled on replicas (e.g. query changes) because the associated
+subsystem is switched off.
 
 ## How to use
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckConfig.java b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckConfig.java
index fc6acc7..2242463 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckConfig.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckConfig.java
@@ -15,6 +15,7 @@
 package com.googlesource.gerrit.plugins.healthcheck;
 
 import static com.google.common.base.Preconditions.checkNotNull;
+import static com.googlesource.gerrit.plugins.healthcheck.check.HealthCheckNames.QUERYCHANGES;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.MoreObjects;
@@ -23,9 +24,11 @@
 import com.google.gerrit.extensions.annotations.PluginName;
 import com.google.gerrit.server.config.AllProjectsName;
 import com.google.gerrit.server.config.AllUsersName;
+import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.config.PluginConfigFactory;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
+import java.util.Collections;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
@@ -48,16 +51,22 @@
   private final AllUsersName allUsersName;
 
   private final Config config;
+  private final boolean isReplica;
+
+  private static final Set<String> HEALTH_CHECK_DISABLED_FOR_REPLICAS =
+      Collections.singleton(QUERYCHANGES);
 
   @Inject
   public HealthCheckConfig(
       PluginConfigFactory configFactory,
       @PluginName String pluginName,
       AllProjectsName allProjectsName,
-      AllUsersName allUsersName) {
+      AllUsersName allUsersName,
+      @GerritServerConfig Config gerritConfig) {
     config = configFactory.getGlobalPluginConfig(pluginName);
     this.allProjectsName = allProjectsName;
     this.allUsersName = allUsersName;
+    isReplica = gerritConfig.getBoolean("container", "slave", false);
   }
 
   @VisibleForTesting
@@ -72,6 +81,7 @@
     }
     allProjectsName = new AllProjectsName("All-Projects");
     allUsersName = new AllUsersName("All-Users");
+    isReplica = false;
   }
 
   @VisibleForTesting
@@ -125,6 +135,9 @@
   }
 
   public boolean healthCheckEnabled(String healthCheckName) {
+    if (isReplica && HEALTH_CHECK_DISABLED_FOR_REPLICAS.contains(healthCheckName)) {
+      return false;
+    }
     return config.getBoolean(
         HEALTHCHECK, checkNotNull(healthCheckName), "enabled", HEALTH_CHECK_ENABLED_DEFAULT);
   }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/filter/HealthCheckStatusFilter.java b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/filter/HealthCheckStatusFilter.java
index e19f18a..b2e91b1 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/healthcheck/filter/HealthCheckStatusFilter.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/healthcheck/filter/HealthCheckStatusFilter.java
@@ -61,14 +61,14 @@
   }
 
   private boolean isStatusCheck(HttpServletRequest httpServletRequest) {
-    return httpServletRequest.getRequestURI().equals("/config/server/healthcheck~status");
+    return httpServletRequest.getRequestURI().matches("(?:/a)?/config/server/healthcheck~status");
   }
 
   private void doStatusCheck(HttpServletResponse httpResponse) throws ServletException {
     try {
       Response<Map<String, Object>> healthStatus =
           (Response<Map<String, Object>>) statusEndpoint.apply(new ConfigResource());
-      String healthStatusJson = gson.toJson(healthStatus);
+      String healthStatusJson = gson.toJson(healthStatus.value());
       if (healthStatus.statusCode() == HttpServletResponse.SC_OK) {
         PrintWriter writer = httpResponse.getWriter();
         writer.print(new String(RestApiServlet.JSON_MAGIC));
diff --git a/src/test/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckIT.java b/src/test/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckIT.java
index 199543b..ef5dc8e 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/healthcheck/HealthCheckIT.java
@@ -21,6 +21,7 @@
 import static com.googlesource.gerrit.plugins.healthcheck.check.HealthCheckNames.JGIT;
 import static com.googlesource.gerrit.plugins.healthcheck.check.HealthCheckNames.QUERYCHANGES;
 
+import com.google.gerrit.acceptance.GerritConfig;
 import com.google.gerrit.acceptance.LightweightPluginDaemonTest;
 import com.google.gerrit.acceptance.RestResponse;
 import com.google.gerrit.acceptance.Sandboxed;
@@ -33,7 +34,10 @@
 import org.junit.Before;
 import org.junit.Test;
 
-@TestPlugin(name = "healthcheck", sysModule = "com.googlesource.gerrit.plugins.healthcheck.Module")
+@TestPlugin(
+    name = "healthcheck",
+    sysModule = "com.googlesource.gerrit.plugins.healthcheck.Module",
+    httpModule = "com.googlesource.gerrit.plugins.healthcheck.HttpModule")
 @Sandboxed
 public class HealthCheckIT extends LightweightPluginDaemonTest {
   Gson gson = new Gson();
@@ -80,6 +84,22 @@
   }
 
   @Test
+  @GerritConfig(name = "container.slave", value = "true")
+  public void shouldReturnJGitCheckForReplicaWhenAuthenticated() throws Exception {
+    RestResponse resp = getHealthCheckStatus();
+    resp.assertOK();
+    assertCheckResult(getResponseJson(resp), JGIT, "passed");
+  }
+
+  @Test
+  @GerritConfig(name = "container.slave", value = "true")
+  public void shouldReturnJGitCheckForReplicaAnonymously() throws Exception {
+    RestResponse resp = getHealthCheckStatusAnonymously();
+    resp.assertOK();
+    assertCheckResult(getResponseJson(resp), JGIT, "passed");
+  }
+
+  @Test
   public void shouldReturnAuthCheck() throws Exception {
     RestResponse resp = getHealthCheckStatus();
 
@@ -115,6 +135,15 @@
   }
 
   @Test
+  @GerritConfig(name = "container.slave", value = "true")
+  public void shouldReturnQueryChangesAsDisabledForSlave() throws Exception {
+    RestResponse resp = getHealthCheckStatus();
+    resp.assertOK();
+
+    assertCheckResult(getResponseJson(resp), QUERYCHANGES, "disabled");
+  }
+
+  @Test
   public void shouldReturnQueryChangesMultipleTimesCheck() throws Exception {
     createChange("refs/for/master");
     getHealthCheckStatus();
@@ -156,6 +185,10 @@
     return adminRestSession.get("/config/server/healthcheck~status");
   }
 
+  private RestResponse getHealthCheckStatusAnonymously() throws IOException {
+    return anonymousRestSession.get("/config/server/healthcheck~status");
+  }
+
   private void assertCheckResult(JsonObject respPayload, String checkName, String result) {
     assertThat(respPayload.has(checkName)).isTrue();
     JsonObject reviewDbStatus = respPayload.get(checkName).getAsJsonObject();