Merge branch 'stable-3.2' into stable-3.3

* stable-3.2:
  Upgrade bazlets to latest stable-3.2 to build with 3.2.5.1 API
  Fix plugin's documentation after 8fb718b
  Upgrade bazlets to latest stable-3.1 to build with 3.1.10 API

Change-Id: I0f3d2bca8a2639d488be390f94c73956e02bc667
diff --git a/BUILD b/BUILD
index 3b896ff..5975b31 100644
--- a/BUILD
+++ b/BUILD
@@ -19,7 +19,10 @@
         "Implementation-URL: https://gerrit-review.googlesource.com/#/admin/projects/plugins/high-availability",
     ],
     resources = glob(["src/main/resources/**/*"]),
-    deps = ["@jgroups//jar"],
+    deps = [
+      "@jgroups//jar",
+      "@global-refdb//jar",
+    ],
 )
 
 junit_tests(
@@ -42,6 +45,7 @@
     visibility = ["//visibility:public"],
     exports = PLUGIN_DEPS + PLUGIN_TEST_DEPS + [
         ":high-availability__plugin",
+        "@global-refdb//jar",
         "@wiremock//jar",
     ],
 )
diff --git a/WORKSPACE b/WORKSPACE
index 83e0599..cdb1696 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -12,7 +12,7 @@
     "gerrit_api",
 )
 
-gerrit_api()
+gerrit_api(version = "3.3.0-SNAPSHOT")
 
 load("//:external_plugin_deps.bzl", "external_plugin_deps")
 
diff --git a/external_plugin_deps.bzl b/external_plugin_deps.bzl
index 0f8b43b..cb3f043 100644
--- a/external_plugin_deps.bzl
+++ b/external_plugin_deps.bzl
@@ -12,3 +12,9 @@
         artifact = "org.jgroups:jgroups:3.6.15.Final",
         sha1 = "755afcfc6c8a8ea1e15ef0073417c0b6e8c6d6e4",
     )
+
+    maven_jar(
+        name = "global-refdb",
+        artifact = "com.gerritforge:global-refdb:3.3.0-rc1",
+        sha1 = "1b005b31c27a30ff10de97f903fa2834051bcadf",
+    )
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java
index 3bd58a3..9af312d 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java
@@ -17,18 +17,19 @@
 import static java.util.concurrent.TimeUnit.HOURS;
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 
+import com.gerritforge.gerrit.globalrefdb.validation.SharedRefDbConfiguration;
+import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.CharMatcher;
 import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.flogger.FluentLogger;
 import com.google.gerrit.common.Nullable;
-import com.google.gerrit.extensions.annotations.PluginName;
 import com.google.gerrit.server.config.ConfigUtil;
-import com.google.gerrit.server.config.PluginConfigFactory;
 import com.google.gerrit.server.config.SitePaths;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
+import java.io.IOException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.Arrays;
@@ -39,7 +40,10 @@
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
+import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.util.FS;
 
 @Singleton
 public class Configuration {
@@ -47,6 +51,7 @@
 
   public static final int DEFAULT_NUM_STRIPED_LOCKS = 10;
   public static final int DEFAULT_TIMEOUT_MS = 5000;
+  public static final String PLUGIN_CONFIG_FILE = "high-availability.config";
 
   // common parameter to peerInfo section
   static final String PEER_INFO_SECTION = "peerInfo";
@@ -70,6 +75,7 @@
   private PeerInfoStatic peerInfoStatic;
   private PeerInfoJGroups peerInfoJGroups;
   private HealthCheck healthCheck;
+  private final SharedRefDbConfiguration sharedRefDb;
 
   public enum PeerInfoStrategy {
     JGROUPS,
@@ -77,9 +83,12 @@
   }
 
   @Inject
-  Configuration(
-      PluginConfigFactory pluginConfigFactory, @PluginName String pluginName, SitePaths site) {
-    Config cfg = pluginConfigFactory.getGlobalPluginConfig(pluginName);
+  Configuration(SitePaths sitePaths) {
+    this(getConfigFile(sitePaths, PLUGIN_CONFIG_FILE), sitePaths);
+  }
+
+  @VisibleForTesting
+  Configuration(Config cfg, SitePaths site) {
     main = new Main(site, cfg);
     autoReindex = new AutoReindex(cfg);
     peerInfo = new PeerInfo(cfg);
@@ -100,6 +109,20 @@
     index = new Index(cfg);
     websession = new Websession(cfg);
     healthCheck = new HealthCheck(cfg);
+    sharedRefDb = new SharedRefDbConfiguration(cfg);
+  }
+
+  private static FileBasedConfig getConfigFile(SitePaths sitePaths, String configFileName) {
+    FileBasedConfig cfg =
+        new FileBasedConfig(sitePaths.etc_dir.resolve(configFileName).toFile(), FS.DETECTED);
+    String fileConfigFileName = cfg.getFile().getPath();
+    try {
+      log.atInfo().log("Loading configuration from {}", fileConfigFileName);
+      cfg.load();
+    } catch (IOException | ConfigInvalidException e) {
+      log.atSevere().withCause(e).log("Unable to load configuration from " + fileConfigFileName);
+    }
+    return cfg;
   }
 
   public Main main() {
@@ -150,6 +173,10 @@
     return healthCheck;
   }
 
+  public SharedRefDbConfiguration sharedRefDb() {
+    return sharedRefDb;
+  }
+
   private static int getInt(Config cfg, String section, String name, int defaultValue) {
     try {
       return cfg.getInt(section, name, defaultValue);
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Module.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Module.java
index 744fac9..ddc294b 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Module.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Module.java
@@ -21,7 +21,7 @@
 import com.ericsson.gerrit.plugins.highavailability.forwarder.rest.RestForwarderModule;
 import com.ericsson.gerrit.plugins.highavailability.index.IndexModule;
 import com.ericsson.gerrit.plugins.highavailability.peers.PeerInfoModule;
-import com.google.inject.AbstractModule;
+import com.google.gerrit.lifecycle.LifecycleModule;
 import com.google.inject.Inject;
 import com.google.inject.Provides;
 import com.google.inject.Singleton;
@@ -29,7 +29,7 @@
 import java.nio.file.Files;
 import java.nio.file.Path;
 
-class Module extends AbstractModule {
+class Module extends LifecycleModule {
   private final Configuration config;
 
   @Inject
@@ -55,6 +55,10 @@
       install(new AutoReindexModule());
     }
     install(new PeerInfoModule(config.peerInfo().strategy()));
+
+    if (config.sharedRefDb().getSharedRefDb().isEnabled()) {
+      listener().to(PluginStartup.class);
+    }
   }
 
   @Provides
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/PluginStartup.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/PluginStartup.java
new file mode 100644
index 0000000..5c19eec
--- /dev/null
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/PluginStartup.java
@@ -0,0 +1,45 @@
+// Copyright (C) 2020 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.ericsson.gerrit.plugins.highavailability;
+
+import com.gerritforge.gerrit.globalrefdb.validation.SharedRefDatabaseWrapper;
+import com.google.gerrit.extensions.events.LifecycleListener;
+import com.google.inject.Inject;
+import com.google.inject.Injector;
+
+/**
+ * Purpose of this class is to copy SharedRefDatabaseWrapper instance from DB injector to plugin
+ * injector. This allows to bind different global ref-db implementations.
+ */
+public class PluginStartup implements LifecycleListener {
+  private SharedRefDatabaseWrapper sharedRefDb;
+  private Injector injector;
+
+  @Inject
+  public PluginStartup(SharedRefDatabaseWrapper sharedRefDb, Injector injector) {
+    this.sharedRefDb = sharedRefDb;
+    this.injector = injector;
+  }
+
+  @Override
+  public void start() {
+    injector.injectMembers(sharedRefDb);
+  }
+
+  @Override
+  public void stop() {
+    // Nothing to do
+  }
+}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/ValidationModule.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/ValidationModule.java
new file mode 100644
index 0000000..74db7d2
--- /dev/null
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/ValidationModule.java
@@ -0,0 +1,70 @@
+// Copyright (C) 2020 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.ericsson.gerrit.plugins.highavailability;
+
+import com.gerritforge.gerrit.globalrefdb.validation.BatchRefUpdateValidator;
+import com.gerritforge.gerrit.globalrefdb.validation.LockWrapper;
+import com.gerritforge.gerrit.globalrefdb.validation.Log4jSharedRefLogger;
+import com.gerritforge.gerrit.globalrefdb.validation.RefUpdateValidator;
+import com.gerritforge.gerrit.globalrefdb.validation.SharedRefDatabaseWrapper;
+import com.gerritforge.gerrit.globalrefdb.validation.SharedRefDbBatchRefUpdate;
+import com.gerritforge.gerrit.globalrefdb.validation.SharedRefDbConfiguration;
+import com.gerritforge.gerrit.globalrefdb.validation.SharedRefDbGitRepositoryManager;
+import com.gerritforge.gerrit.globalrefdb.validation.SharedRefDbRefDatabase;
+import com.gerritforge.gerrit.globalrefdb.validation.SharedRefDbRefUpdate;
+import com.gerritforge.gerrit.globalrefdb.validation.SharedRefDbRepository;
+import com.gerritforge.gerrit.globalrefdb.validation.SharedRefLogger;
+import com.gerritforge.gerrit.globalrefdb.validation.dfsrefdb.CustomSharedRefEnforcementByProject;
+import com.gerritforge.gerrit.globalrefdb.validation.dfsrefdb.DefaultSharedRefEnforcement;
+import com.gerritforge.gerrit.globalrefdb.validation.dfsrefdb.SharedRefEnforcement;
+import com.google.gerrit.extensions.config.FactoryModule;
+import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.inject.Inject;
+import com.google.inject.Scopes;
+
+public class ValidationModule extends FactoryModule {
+  final Configuration configuration;
+
+  @Inject
+  public ValidationModule(Configuration configuration) {
+    this.configuration = configuration;
+  }
+
+  @Override
+  protected void configure() {
+    factory(SharedRefDbRepository.Factory.class);
+    factory(SharedRefDbRefDatabase.Factory.class);
+    factory(SharedRefDbRefUpdate.Factory.class);
+    factory(SharedRefDbBatchRefUpdate.Factory.class);
+    factory(RefUpdateValidator.Factory.class);
+    factory(BatchRefUpdateValidator.Factory.class);
+
+    bind(SharedRefDbConfiguration.class).toInstance(configuration.sharedRefDb());
+
+    bind(SharedRefDatabaseWrapper.class).in(Scopes.SINGLETON);
+    bind(SharedRefLogger.class).to(Log4jSharedRefLogger.class);
+    factory(LockWrapper.Factory.class);
+
+    bind(GitRepositoryManager.class).to(SharedRefDbGitRepositoryManager.class);
+
+    if (configuration.sharedRefDb().getSharedRefDb().getEnforcementRules().isEmpty()) {
+      bind(SharedRefEnforcement.class).to(DefaultSharedRefEnforcement.class).in(Scopes.SINGLETON);
+    } else {
+      bind(SharedRefEnforcement.class)
+          .to(CustomSharedRefEnforcementByProject.class)
+          .in(Scopes.SINGLETON);
+    }
+  }
+}
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/GroupReindexRunnable.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/GroupReindexRunnable.java
index e37234c..1d31ebc 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/GroupReindexRunnable.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/GroupReindexRunnable.java
@@ -15,7 +15,7 @@
 package com.ericsson.gerrit.plugins.highavailability.autoreindex;
 
 import com.ericsson.gerrit.plugins.highavailability.forwarder.rest.AbstractIndexRestApiServlet;
-import com.google.gerrit.common.data.GroupReference;
+import com.google.gerrit.entities.GroupReference;
 import com.google.gerrit.server.group.db.Groups;
 import com.google.gerrit.server.util.OneOffRequestContext;
 import com.google.inject.Inject;
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/ChangeCheckerImpl.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/ChangeCheckerImpl.java
index fe04ee9..6587acf 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/ChangeCheckerImpl.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/index/ChangeCheckerImpl.java
@@ -17,7 +17,7 @@
 import com.ericsson.gerrit.plugins.highavailability.forwarder.IndexEvent;
 import com.google.common.flogger.FluentLogger;
 import com.google.gerrit.entities.Change;
-import com.google.gerrit.entities.Comment;
+import com.google.gerrit.entities.HumanComment;
 import com.google.gerrit.server.CommentsUtil;
 import com.google.gerrit.server.change.ChangeFinder;
 import com.google.gerrit.server.git.GitRepositoryManager;
@@ -144,7 +144,7 @@
   private long getTsFromChangeAndDraftComments(ChangeNotes notes) {
     Change change = notes.getChange();
     Timestamp changeTs = change.getLastUpdatedOn();
-    for (Comment comment : commentsUtil.draftByChange(changeNotes.get())) {
+    for (HumanComment comment : commentsUtil.draftByChange(changeNotes.get())) {
       Timestamp commentTs = comment.writtenOn;
       changeTs = commentTs.after(changeTs) ? commentTs : changeTs;
     }
diff --git a/src/main/resources/Documentation/about.md b/src/main/resources/Documentation/about.md
index fd0b56e..851f584 100644
--- a/src/main/resources/Documentation/about.md
+++ b/src/main/resources/Documentation/about.md
@@ -7,10 +7,10 @@
 * sharing the git repositories using a shared file system (e.g. NFS)
 * behind a load balancer (e.g. HAProxy)
 
-Currently, the mode supported is one active instance and multiple backup
-(passive) instances but eventually the plan is to support `n` active instances.
-In the active/passive mode, the active instance is handling all traffic while
-the passives are kept updated to be always ready to take over.
+Default mode is one active instance and multiple backup (passive) instances
+but `n` active instances can be configured. In the active/passive mode, the active
+instance is handling all traffic while the passives are kept updated to be always
+ready to take over.
 
 Even if git repositories are shared by the instances, there are a few areas
 of concern in order to be able to switch traffic between instances in a
@@ -46,7 +46,7 @@
 The built-in Gerrit H2 based web session cache is replaced with a file based
 implementation that is shared amongst the instances.
 
-## Setup
+## Active/passive setup
 
 Prerequisites:
 
@@ -103,3 +103,72 @@
 
 For further information and supported options, refer to [config](config.md)
 documentation.
+
+## Active/active setup
+
+Prerequisites:
+
+* Git repositories must be located on a shared file system
+* A directory on a shared file system must be available for @PLUGIN@ to use
+* An implementation of global-refdb (e.g. Zookeeper) must be accessible from all the active
+instances
+
+For the instances:
+
+* Configure gerrit.basePath in gerrit.config to the shared repositories location
+* Configure gerrit.serverId in gerrit.config based on [config](config.md)'s introduction
+* Install and configure this @PLUGIN@ plugin [further](config.md) or based on example
+configuration
+* Install @PLUGIN@ plugin as a database module in $GERRIT_SITE/lib(please note that
+@PLUGIN plugin must be installed as a plugin and as a database module) and add
+`installDbModule = com.ericsson.gerrit.plugins.highavailability.ValidationModule`
+to the gerrit section in gerrit.config
+* Install [global-refdb library](https://mvnrepository.com/artifact/com.gerritforge/global-refdb) as a library module in $GERRIT_SITE/lib and add
+`installModule = com.gerritforge.gerrit.globalrefdb.validation.LibModule` to the gerrit
+section in gerrit.config
+* Install and configure [zookeeper-refdb plugin](https://gerrit-ci.gerritforge.com/view/Plugins-master/job/plugin-zookeeper-refdb-bazel-master) based on [config.md](https://gerrit.googlesource.com/plugins/zookeeper-refdb/+/refs/heads/master/src/main/resources/Documentation/config.md)
+* Configure ref-database.enabled = true in @PLUGIN@.config to enable validation with
+global-refdb.
+
+Here is an example of the minimal @PLUGIN@.config:
+
+Active instance one
+
+```
+[main]
+  sharedDirectory = /directory/accessible/from/both/instances
+
+[peerInfo "static"]
+  url = http://backupNodeHost1:8081/
+
+[http]
+  user = username
+  password = password
+
+[ref-database]
+  enabled = true
+```
+
+Active instance two
+
+```
+[main]
+  sharedDirectory = /directory/accessible/from/both/instances
+
+[peerInfo "static"]
+  url = http://primaryNodeHost:8080/
+
+[http]
+  user = username
+  password = password
+
+[ref-database]
+  enabled = true
+```
+
+Minimal zookeeper-refdb.config for both active instances:
+
+```
+[ref-database "zookeeper"]
+  connectString = zookeeperhost:2181
+```
\ No newline at end of file
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index f711fe3..2976de5 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -235,6 +235,32 @@
 ```healthcheck.enable```
 :   Whether to enable the health check endpoint. Defaults to 'true'.
 
+```ref-database.enabled```
+:   Enable the use of a global ref-database. Defaults to 'false'.
+
+```ref-database.enforcementRules.<policy>```
+:   Level of consistency enforcement across sites on a project:refs basis.
+    Supports two values for enforcing the policy on multiple projects or refs.
+    If the project or ref is omitted, apply the policy to all projects or all refs.
+
+    The <policy> can be one of the following values:
+
+    1. REQUIRED - Throw an exception if a git ref-update is processed against
+    a local ref not yet in sync with the global ref-database.
+    The user transaction is cancelled. LOCK_FAILURE is reported upstream.
+
+    2. IGNORED - Do not validate against the global ref-database.
+
+    *Example:*
+    ```
+    [ref-database "enforcementRules"]
+       IGNORED = AProject:/refs/heads/feature
+    ```
+
+    Ignore the alignment with the global ref-db for AProject on refs/heads/feature.
+
+    Defaults to no rule. All projects are REQUIRED to be consistent on all refs.
+
 File 'gerrit.config'
 --------------------
 
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java
index a9537bd..4bfac28 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java
@@ -62,7 +62,6 @@
 import static com.google.common.truth.Truth8.assertThat;
 import static java.util.concurrent.TimeUnit.SECONDS;
 import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.when;
 
 import com.ericsson.gerrit.plugins.highavailability.Configuration.PeerInfoStrategy;
 import com.google.common.collect.ImmutableList;
@@ -104,12 +103,11 @@
   @Before
   public void setUp() throws IOException {
     globalPluginConfig = new Config();
-    when(pluginConfigFactoryMock.getGlobalPluginConfig(PLUGIN_NAME)).thenReturn(globalPluginConfig);
     sitePaths = new SitePaths(SITE_PATH);
   }
 
   private Configuration getConfiguration() {
-    return new Configuration(pluginConfigFactoryMock, PLUGIN_NAME, sitePaths);
+    return new Configuration(globalPluginConfig, sitePaths);
   }
 
   @Test
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/AbstractIndexForwardingIT.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/AbstractIndexForwardingIT.java
index 5843908..83f86d0 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/AbstractIndexForwardingIT.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/index/AbstractIndexForwardingIT.java
@@ -25,15 +25,19 @@
 import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
 import static com.google.common.truth.Truth.assertThat;
 
+import com.ericsson.gerrit.plugins.highavailability.Configuration;
 import com.github.tomakehurst.wiremock.junit.WireMockRule;
 import com.google.gerrit.acceptance.LightweightPluginDaemonTest;
 import com.google.gerrit.acceptance.NoHttpd;
 import com.google.gerrit.acceptance.TestPlugin;
 import com.google.gerrit.acceptance.UseLocalDisk;
-import com.google.gerrit.acceptance.config.GlobalPluginConfig;
+import com.google.gerrit.server.config.SitePaths;
+import com.google.inject.Inject;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import org.apache.http.HttpStatus;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.util.FS;
 import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
@@ -50,17 +54,23 @@
 
   @Rule public WireMockRule wireMockRule = new WireMockRule(options().port(PORT));
 
+  @Inject SitePaths sitePaths;
+
   @Override
   public void setUpTestPlugin() throws Exception {
     givenThat(any(anyUrl()).willReturn(aResponse().withStatus(HttpStatus.SC_NO_CONTENT)));
+    FileBasedConfig fileBasedConfig =
+        new FileBasedConfig(
+            sitePaths.etc_dir.resolve(Configuration.PLUGIN_CONFIG_FILE).toFile(), FS.DETECTED);
+    fileBasedConfig.setString("peerInfo", "static", "url", URL);
+    fileBasedConfig.setInt("http", null, "retryInterval", 100);
+    fileBasedConfig.save();
     beforeAction();
     super.setUpTestPlugin();
   }
 
   @Test
   @UseLocalDisk
-  @GlobalPluginConfig(pluginName = "high-availability", name = "peerInfo.static.url", value = URL)
-  @GlobalPluginConfig(pluginName = "high-availability", name = "http.retryInterval", value = "100")
   public void testIndexForwarding() throws Exception {
     String expectedRequest = getExpectedRequest();
     CountDownLatch expectedRequestLatch = new CountDownLatch(1);