Merge branch 'stable-3.12' into stable-3.13

* stable-3.12:
  Reduce HTTP check internal to 1s in Docker tests
  Use healthcheck plugin for Docker tests

Change-Id: I83572cf9efff6c0e08c2c1b6962f68354743e41a
diff --git a/BUILD b/BUILD
index 3735cb3..4beff6e 100644
--- a/BUILD
+++ b/BUILD
@@ -21,7 +21,6 @@
     resources = glob(["src/main/resources/**/*"]),
     deps = [
         ":global-refdb-neverlink",
-        "@auto-value//jar",
         "@failsafe//jar",
         "@jgroups-kubernetes//jar",
         "@jgroups//jar",
diff --git a/README.md b/README.md
index fcf0566..11a33b2 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
 # Gerrit high-availability plugin
 
-This plugin allows deploying a cluster of multiple Gerrit primaries
-on the same data-center sharing the same Git repositories.
+This plugin allows deploying a cluster of multiple Gerrit primary servers
+in the same data-center sharing the same Git repositories.
 
 Requirements for the Gerrit primaries are:
 
@@ -17,6 +17,18 @@
 
 Refer to the [build instructions in the plugin documentation](src/main/resources/Documentation/build.md).
 
+## Installation
+
+Install
+
+- the `high-availability` plugin in the Gerrit site's `plugins` folder.
+
+> **NOTE** the `global-refdb` lib module in the Gerrit site's `lib` folder, even if it is not used or referenced as libModule in the `gerrit.config`, because of a bug in the high-availability plugin initialisation sequence.
+
+In active-active deployments with multiple Gerrit primaries, installation of a global-refdb
+implementation is needed to maintain consistent ref updates across all
+Gerrit primary sites.
+
 ## Sample configuration for two Gerrit primaries in high-availability
 
 Assuming that the Gerrit primaries in the clusters are `gerrit-01.mycompany.com` and
@@ -76,7 +88,11 @@
 
 It is the simplest and safest configuration, where only one Gerrit primary at a
 time serves the incoming requests.
+<<<<<<< HEAD
+In case of failure of the active primary, the traffic is forwarded to the backup.
+=======
 In case of failure of the primary, the traffic is forwarded to the backup.
+>>>>>>> stable-3.12
 
 Assuming a load-balancing implemented using [HAProxy](http://www.haproxy.org/)
 associated with the domain name `gerrit.mycompany.com`, exposing Gerrit cluster nodes
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/ValidationModule.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/ValidationModule.java
index 9229d01..c770092 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/ValidationModule.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/ValidationModule.java
@@ -26,9 +26,6 @@
 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.extensions.registration.DynamicSet;
 import com.google.gerrit.server.ExceptionHook;
@@ -60,14 +57,6 @@
 
     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);
-    }
-
     DynamicSet.bind(binder(), ExceptionHook.class).to(SharedRefDbExceptionHook.class);
   }
 }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/cache/CachePatternMatcher.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/cache/CachePatternMatcher.java
index baf512f..ac6ea4c 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/cache/CachePatternMatcher.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/cache/CachePatternMatcher.java
@@ -26,7 +26,7 @@
 @Singleton
 class CachePatternMatcher {
   private static final List<String> DEFAULT_PATTERNS =
-      ImmutableList.of("^groups.*", "ldap_usernames", "projects", "sshkeys");
+      ImmutableList.of("^groups.*", "ldap_usernames", "projects", "sshkeys", "tokens");
 
   private final Pattern pattern;
 
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/cache/Constants.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/cache/Constants.java
index b456998..d4fab98 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/cache/Constants.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/cache/Constants.java
@@ -22,6 +22,7 @@
   public static final String GROUPS_BYINCLUDE = "groups_byinclude";
   public static final String GROUPS_MEMBERS = "groups_members";
   public static final String PROJECTS = "projects";
+  public static final String TOKENS = "tokens";
 
   private Constants() {}
 }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/CacheKeyJsonParser.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/CacheKeyJsonParser.java
index ba28650..b8f5e9c 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/CacheKeyJsonParser.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/CacheKeyJsonParser.java
@@ -44,6 +44,7 @@
     // Need to add a case for 'adv_bases'
     switch (cacheName) {
       case Constants.ACCOUNTS:
+      case Constants.TOKENS:
         return id.get() == null ? null : Account.id(id.get().getAsInt());
       case Constants.GROUPS:
         return id.get() == null ? null : AccountGroup.id(id.get().getAsInt());
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/JGroupsPeerInfoProvider.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/JGroupsPeerInfoProvider.java
index 63f65d6..6079804 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/JGroupsPeerInfoProvider.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/peers/jgroups/JGroupsPeerInfoProvider.java
@@ -14,10 +14,10 @@
 
 package com.ericsson.gerrit.plugins.highavailability.peers.jgroups;
 
-import autovalue.shaded.com.google.common.collect.ImmutableMap;
 import com.ericsson.gerrit.plugins.highavailability.Configuration;
 import com.ericsson.gerrit.plugins.highavailability.peers.PeerInfo;
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.flogger.FluentLogger;
 import com.google.gerrit.extensions.events.LifecycleListener;
diff --git a/src/main/resources/Documentation/about.md b/src/main/resources/Documentation/about.md
index 6fcd2e2..f62c035 100644
--- a/src/main/resources/Documentation/about.md
+++ b/src/main/resources/Documentation/about.md
@@ -27,15 +27,18 @@
 sharing or synchronizing them.
 
 #### Caches
+
 Every time a cache eviction occurs in one of the instances, the eviction will be
 forwarded the other nodes so their caches do not contain stale entries.
 
 #### Secondary indexes
+
 Every time the secondary index is modified in one of the instances, e.g., a change
 is added, updated or removed from the index, the others instances index are updated
 accordingly. This way, both indexes are kept synchronized.
 
 #### Stream events
+
 Every time a stream event occurs in one of the instances
 (see [more events info](https://gerrit-review.googlesource.com/Documentation/cmd-stream-events.html#events)),
 the event is forwarded to the other instances which re-plays it. This way, the output
@@ -43,6 +46,7 @@
 connected to.
 
 #### Web session
+
 The built-in Gerrit H2 based web session cache is replaced with a file based
 implementation that is shared amongst the instances.
 
@@ -55,8 +59,8 @@
 
 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
+* 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 below.
 
 Here is an example of the minimal @PLUGIN@.config:
@@ -110,25 +114,34 @@
 
 * 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
+* An implementation of `global-refdb` (e.g. Zookeeper) must be accessible from all the active
+  instances to maintain consistent ref updates across all Gerrit primary sites
+
+The following `global-refdb` implementations are available:
+
+* [zookeeper-refdb plugin](https://gerrit.googlesource.com/plugins/zookeeper-refdb/+/refs/heads/master)
+  using Apache Zookeeper
+* [aws-dynamodb-refdb plugin](https://gerrit.googlesource.com/plugins/aws-dynamodb-refdb/+/refs/heads/master)
+  using AWS DynamoDB
+* [spanner-refdb plugin](https://gerrit.googlesource.com/plugins/spanner-refdb/+/refs/heads/master)
+  using Google Cloud Spanner
 
 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
+* 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 @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 <br/>
+`installDbModule = com.ericsson.gerrit.plugins.highavailability.ValidationModule` <br/>
+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  <br/>
+`installModule = com.gerritforge.gerrit.globalrefdb.validation.LibModule` <br/>
+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.
+* Configure `ref-database.enabled = true` in @PLUGIN@.config to enable validation with
+`global-refdb`.
 
 Here is an example of the minimal @PLUGIN@.config:
 
@@ -166,12 +179,13 @@
   enabled = true
 ```
 
-Minimal zookeeper-refdb.config for both active instances:
+Minimal `zookeeper-refdb.config` for both active instances:
 
 ```
 [ref-database "zookeeper"]
   connectString = zookeeperhost:2181
 ```
+
 ### Last index update timestamp storage
 
 The plugin keeps track of the timestamp when it lastly updated an index.
@@ -180,6 +194,7 @@
 sync with the primary, for example, after a node being offline for a long time.
 
 The HA plugin keeps the last update timestamp for each index in the following files:
+
 * `<gerrit_home>/data/high-availability/account`
 * `<gerrit_home>/data/high-availability/change`
 
diff --git a/src/test/README.md b/src/test/README.md
index 80fe2e4..b0aa3c4 100644
--- a/src/test/README.md
+++ b/src/test/README.md
@@ -1,8 +1,8 @@
 # Gerrit high-availability docker setup example
 
 The Docker Compose project in the docker directory contains a simple test
-environment of two Gerrit primaries in HA configuration, with their git repos
-hosted on NFS filesystem.
+environment of two Gerrit primary servers in HA configuration, with their
+git repos hosted on NFS filesystem.
 
 ## How to build
 
diff --git a/src/test/docker/gerrit/Dockerfile b/src/test/docker/gerrit/Dockerfile
index ebb4b84..d18e060 100644
--- a/src/test/docker/gerrit/Dockerfile
+++ b/src/test/docker/gerrit/Dockerfile
@@ -11,7 +11,7 @@
     nfs-utils \
     && yum -y clean all
 
-ENV GERRIT_BRANCH stable-3.12
+ENV GERRIT_BRANCH stable-3.13
 
 # Add gerrit user
 RUN adduser -p -m --uid 1000 gerrit --home-dir /home/gerrit
@@ -42,7 +42,7 @@
     /var/gerrit/lib/global-refdb.jar
 
 ADD --chown=gerrit:gerrit \
-    "https://gerrit-ci.gerritforge.com/job/plugin-zookeeper-refdb-bazel-$GERRIT_BRANCH/lastSuccessfulBuild/artifact/bazel-bin/plugins/zookeeper-refdb/zookeeper-refdb.jar" \
+    "https://gerrit-ci.gerritforge.com/job/plugin-zookeeper-refdb-gh-bazel-$GERRIT_BRANCH/lastSuccessfulBuild/artifact/bazel-bin/plugins/zookeeper-refdb/zookeeper-refdb.jar" \
     /var/gerrit/plugins/zookeeper-refdb.jar
 
 ADD --chown=gerrit:gerrit \
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 b51e1a0..0fb7dad 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java
@@ -217,9 +217,6 @@
 
     globalPluginConfig.setInt(HTTP_SECTION, null, CONNECTION_TIMEOUT_KEY, TIMEOUT);
     assertThat(getConfiguration().http().connectionTimeout().toMillis()).isEqualTo(TIMEOUT);
-
-    globalPluginConfig.setString(HTTP_SECTION, null, CONNECTION_TIMEOUT_KEY, INVALID_INT);
-    assertThat(getConfiguration().http().connectionTimeout()).isEqualTo(DEFAULT_TIMEOUT);
   }
 
   @Test
@@ -228,9 +225,6 @@
 
     globalPluginConfig.setInt(HTTP_SECTION, null, SOCKET_TIMEOUT_KEY, TIMEOUT);
     assertThat(getConfiguration().http().socketTimeout().toMillis()).isEqualTo(TIMEOUT);
-
-    globalPluginConfig.setString(HTTP_SECTION, null, SOCKET_TIMEOUT_KEY, INVALID_INT);
-    assertThat(getConfiguration().http().socketTimeout()).isEqualTo(DEFAULT_TIMEOUT);
   }
 
   @Test
@@ -256,9 +250,6 @@
 
     globalPluginConfig.setInt(HTTP_SECTION, null, RETRY_INTERVAL_KEY, RETRY_INTERVAL);
     assertThat(getConfiguration().http().retryInterval().toMillis()).isEqualTo(RETRY_INTERVAL);
-
-    globalPluginConfig.setString(HTTP_SECTION, null, RETRY_INTERVAL_KEY, INVALID_INT);
-    assertThat(getConfiguration().http().retryInterval()).isEqualTo(DEFAULT_RETRY_INTERVAL);
   }
 
   @Test
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CachePatternMatcherTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CachePatternMatcherTest.java
index caf50b9..088b42e 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CachePatternMatcherTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CachePatternMatcherTest.java
@@ -47,6 +47,7 @@
             "ldap_usernames",
             "projects",
             "sshkeys",
+            "tokens",
             "my_cache_a",
             "my_cache_b",
             "other")) {
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/CacheRestApiServletTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/CacheRestApiServletTest.java
index e4ffd59..58c0aef 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/CacheRestApiServletTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/CacheRestApiServletTest.java
@@ -87,6 +87,12 @@
   }
 
   @Test
+  public void evictTokensCache() throws Exception {
+    configureMocksFor(Constants.TOKENS);
+    verifyResponseIsOK();
+  }
+
+  @Test
   public void evictDefault() throws Exception {
     configureMocksFor(Constants.PROJECTS);
     verifyResponseIsOK();
@@ -134,6 +140,8 @@
     } else if (Constants.GROUPS_BYINCLUDE.equals(cacheName)
         || Constants.GROUPS_MEMBERS.equals(cacheName)) {
       when(readerMock.readLine()).thenReturn("{\"uuid\":\"abcd1234\"}");
+    } else if (Constants.TOKENS.equals(cacheName)) {
+      when(readerMock.readLine()).thenReturn("{\"id\":\"1234\"}");
     } else {
       when(readerMock.readLine()).thenReturn("{}");
     }