Merge branch 'stable-3.1' into stable-3.2

* stable-3.1:
  Serve reindexing simulating a GET request for /meta ref caching
  Auto-reload the indexTs file for auto-reindexing
  Download plugins from archive-ci.gerritforge.com
  Pin haproxy to 1.8.30-buster and fix associated issues
  Fix issue with change indexing during the NoteDb online migration
  Remove references to ReviewDb in README.md

The change Ife8b18b40b: "Serve reindexing simulating a GET request for
/meta ref caching" was reverted during the merge.

Change-Id: I01914e83da2753dfb07021e9c1cd653ba4018b42
diff --git a/BUILD b/BUILD
index c3f5a11..3b896ff 100644
--- a/BUILD
+++ b/BUILD
@@ -25,6 +25,7 @@
 junit_tests(
     name = "high-availability_tests",
     srcs = glob(["src/test/java/**/*.java"]),
+    javacopts = ["-Xep:DoNotMock:OFF"],
     resources = glob(["src/test/resources/**/*"]),
     tags = [
         "high-availability",
diff --git a/WORKSPACE b/WORKSPACE
index 6969594..acca707 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -3,7 +3,7 @@
 load("//:bazlets.bzl", "load_bazlets")
 
 load_bazlets(
-    commit = "87fd5f0d0a89d01df13deaf2d21a4bdb3bc03cfd",
+    commit = "8dc0767541f16b35d2136eccebffd9ebe2b81133",
     #local_path = "/home/<user>/projects/bazlets",
 )
 
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 093628e..af1c4c3 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java
@@ -17,6 +17,7 @@
 import static java.util.concurrent.TimeUnit.HOURS;
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 
+import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.CharMatcher;
 import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableList;
@@ -77,8 +78,9 @@
     STATIC
   }
 
+  @VisibleForTesting
   @Inject
-  Configuration(
+  public Configuration(
       PluginConfigFactory pluginConfigFactory, @PluginName String pluginName, SitePaths site) {
     Config cfg = pluginConfigFactory.getGlobalPluginConfig(pluginName);
     main = new Main(site, cfg);
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/IndexTs.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/IndexTs.java
index b4db602..a6539e0 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/IndexTs.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/IndexTs.java
@@ -163,12 +163,12 @@
     currCtx.onlyWithContext(
         (ctx) -> {
           try {
-            ChangeNotes changeNotes = changeFinder.findOne(projectName + "~" + id);
+            Optional<ChangeNotes> changeNotes = changeFinder.findOne(projectName + "~" + id);
             update(
                 IndexName.CHANGE,
-                changeNotes == null
+                !changeNotes.isPresent()
                     ? LocalDateTime.now()
-                    : changeNotes.getChange().getLastUpdatedOn().toLocalDateTime());
+                    : changeNotes.get().getChange().getLastUpdatedOn().toLocalDateTime());
           } catch (Exception e) {
             log.atWarning().withCause(e).log("Unable to update the latest TS for change %d", id);
           }
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 0f43eaf..baf512f 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("accounts", "^groups.*", "ldap_usernames", "projects", "sshkeys");
+      ImmutableList.of("^groups.*", "ldap_usernames", "projects", "sshkeys");
 
   private final Pattern pattern;
 
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedAwareEventBroker.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedAwareEventBroker.java
index f156da4..fb651b7 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedAwareEventBroker.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedAwareEventBroker.java
@@ -14,6 +14,7 @@
 
 package com.ericsson.gerrit.plugins.highavailability.forwarder;
 
+import com.google.gerrit.server.config.GerritInstanceId;
 import com.google.gerrit.server.events.Event;
 import com.google.gerrit.server.events.EventBroker;
 import com.google.gerrit.server.events.EventListener;
@@ -23,6 +24,8 @@
 import com.google.gerrit.server.plugincontext.PluginSetContext;
 import com.google.gerrit.server.project.ProjectCache;
 import com.google.inject.Inject;
+import java.util.Objects;
+import javax.annotation.Nullable;
 
 class ForwardedAwareEventBroker extends EventBroker {
 
@@ -32,12 +35,30 @@
       PluginSetContext<EventListener> unrestrictedListeners,
       PermissionBackend permissionBackend,
       ProjectCache projectCache,
-      Factory notesFactory) {
-    super(listeners, unrestrictedListeners, permissionBackend, projectCache, notesFactory);
+      Factory notesFactory,
+      @Nullable @GerritInstanceId String gerritInstanceId) {
+    super(
+        listeners,
+        unrestrictedListeners,
+        permissionBackend,
+        projectCache,
+        notesFactory,
+        gerritInstanceId);
+  }
+
+  private boolean isProducedByLocalInstance(Event event) {
+    return Objects.equals(event.instanceId, gerritInstanceId);
   }
 
   @Override
   protected void fireEventForUnrestrictedListeners(Event event) {
+    // An event should not be dispatched when it is "forwarded".
+    // Meaning, it was either produced somewhere else
+    if (!isProducedByLocalInstance(event)) {
+      Context.setForwardedEvent(true);
+    }
+    // or it was consumed by the high-availability rest endpoint and
+    // thus the context of its consumption has already been set to "forwarded".
     if (!Context.isForwardedEvent()) {
       super.fireEventForUnrestrictedListeners(event);
     }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/AbstractIndexRestApiServlet.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/AbstractIndexRestApiServlet.java
index 6b23588..a567f61 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/AbstractIndexRestApiServlet.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/rest/AbstractIndexRestApiServlet.java
@@ -22,7 +22,6 @@
 import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwardedIndexingHandler.Operation;
 import com.ericsson.gerrit.plugins.highavailability.forwarder.IndexEvent;
 import com.google.common.base.Charsets;
-import com.google.gerrit.server.cache.PerThreadCache;
 import com.google.gerrit.server.events.EventGson;
 import com.google.gson.Gson;
 import java.io.IOException;
@@ -30,7 +29,6 @@
 import java.io.Reader;
 import java.util.Optional;
 import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletRequestWrapper;
 import javax.servlet.http.HttpServletResponse;
 
 public abstract class AbstractIndexRestApiServlet<T> extends AbstractRestApiServlet {
@@ -91,25 +89,7 @@
     String path = req.getRequestURI();
     T id = parse(path.substring(path.lastIndexOf('/') + 1));
 
-    /**
-     * Since [1] the change notes /meta refs are cached for all the incoming GET/HEAD REST APIs;
-     * however, the high-availability indexing API is a POST served by a regular servlet and
-     * therefore won't have any caching, which is problematic because of the high number of
-     * associated refs lookups generated.
-     *
-     * <p>Simulate an incoming GET request for allowing caching of the /meta refs lookups.
-     *
-     * <p>[1] https://gerrit-review.googlesource.com/c/gerrit/+/334539/17
-     */
-    HttpServletRequestWrapper simulatedGetRequestForCaching =
-        new HttpServletRequestWrapper(req) {
-          @Override
-          public String getMethod() {
-            return "GET";
-          }
-        };
-
-    try (PerThreadCache unused = PerThreadCache.create(simulatedGetRequestForCaching)) {
+    try {
       forwardedIndexingHandler.index(id, operation, parseBody(req));
       rsp.setStatus(SC_NO_CONTENT);
     } catch (IOException e) {
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 23712be..945cefa 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
@@ -87,7 +87,7 @@
   @Override
   public Optional<ChangeNotes> getChangeNotes() {
     try (ManualRequestContext ctx = oneOffReqCtx.open()) {
-      changeNotes = Optional.ofNullable(changeFinder.findOne(changeId));
+      changeNotes = changeFinder.findOne(changeId);
       return changeNotes;
     }
   }
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index 5186bd1..3b1fee2 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -3,8 +3,8 @@
 =========================
 
 The @PLUGIN@ plugin must be installed on all the instances. Each instance should
-be configured with the same [gerrit.serverId](https://gerrit-documentation.storage.googleapis.com/Documentation/3.1.0/config-gerrit.html#gerrit.serverId).
-If there are existing changes in [NoteDb](https://gerrit-documentation.storage.googleapis.com/Documentation/3.1.0/note-db.html)
+be configured with the same [gerrit.serverId](https://gerrit-documentation.storage.googleapis.com/Documentation/3.2.0/config-gerrit.html#gerrit.serverId).
+If there are existing changes in [NoteDb](https://gerrit-documentation.storage.googleapis.com/Documentation/3.2.0/note-db.html)
 made with another `serverId`, then this plugin might not be able to access them.
 Likewise, if the HA gerrit.serverIds differ, then changes conveyed by one
 instance will not be accessible by the other.
@@ -238,3 +238,23 @@
 
 ```healthcheck.enable```
 :   Whether to enable the health check endpoint. Defaults to 'true'.
+
+File 'gerrit.config'
+--------------------
+
+```gerrit.instanceId```
+:   Optional identifier for this Gerrit instance.
+[[docs](https://gerrit-documentation.storage.googleapis.com/Documentation/3.2.0/config-gerrit.html#gerrit.instanceId)].
+
+Whilst this is not, specifically, a high-availability plugin configuration, it plays
+an important role on which events are forwarded to peers.
+
+If `instanceId` is set, events produced by that Gerrit instance will contain its
+origin in the `instanceId` field, allowing to track where they are coming from.
+
+The high-availability plugin will check the `instanceId` value to decide whether
+an event should be forwarded: events that originated from different Gerrit instances
+will not be forwarded.
+
+When neither `gerrit.instanceId` nor `event.instanceId` are set, it is not possible
+to identify the origin of the event and thus the event is always forwarded.
diff --git a/src/test/README.md b/src/test/README.md
index c7a5225..1b8e4a2 100644
--- a/src/test/README.md
+++ b/src/test/README.md
@@ -1,8 +1,94 @@
-# About this directory structure
+# Gerrit high-availability docker setup example
 
-Refer to docker/README.md for more about these directory structures:
+The Docker Compose project in the docker directory contains a simple test 
+environment of two Gerrit masters in HA configuration.
+
+## How to build
+
+The project can be built using docker-compose.
+
+To build the Docker VMs:
+```
+  $ docker-compose build
+```
+
+### Building the Docker VMs using a non-default user id
 
 ```
-  ./resources/com
-  ./scala
+  $ export GERRIT_UID=$(id -u)
+  $ docker-compose build --build-arg GERRIT_UID
+```
+
+Above, exporting that UID is optional and will be 1000 by default.
+Build the gerrit images this way only if the user with id 1000 on your
+host is not owned by you. For example, some corporate environments use a
+restricted 1000 user (id). In that case, the containerized application
+may fail to write towards the host (through volumes).
+
+That UID will be the one set for the containerized gerrit user. Latter's
+group will remain as default (1000). This is because groups known from
+the host need to be redefined for containers. Setting that user's group
+in the container is not necessary for writing anyway, as opposed to its
+user id. The individual gerrit user's writing permission does suffice.
+
+## How to run
+
+Use the 'up' target to startup the Docker Compose VMs.
+
+```
+  $ docker-compose up
+```
+
+# Gerrit high-availability local setup example
+
+ 1. Init gerrit instances with high-availability plugin installed:
+    1. Optionally, set http port of those instance to 8081 and 8082.
+    2. Make sure ssh ports on those instances are different. (i.e. 29418 and 29419)
+    3. Make sure instances share the same git repo.
+    4. Create and provide shared directory to those instances.
+ 2. Set up high-availability plugin.
+    1. main.sharedDirectory = "the created shared directory above".
+    2. peerInfo.strategy = static
+    3. peerInfo "static".url = other_instance_url (i.e http://localhost:8081 or http://localhost:8082)
+
+## How to test
+
+Consider the
+[instructions](https://gerrit-review.googlesource.com/Documentation/dev-e2e-tests.html)
+on how to use Gerrit core's Gatling framework, to run non-core test
+scenarios such as this plugin one below:
+
+```
+  $ sbt "gatling:testOnly com.ericsson.gerrit.plugins.highavailability.scenarios.CloneUsingHAGerrit2"
+```
+
+This is a scenario that can serve as an example for how to start
+testing an HA Gerrit system. That scenario tries to clone a project
+created on gerrit 1 (port 8081) but from gerrit 2 (on 8082). The
+scenario therefore expects Gerrit HA to have properly synchronized
+the new project from 1 to 2. That project gets deleted after, here
+using HA Gerrit straight (through default http port 80).
+
+Scenario scala source files and their companion json resource ones are
+stored under the usual src/test directories. That structure follows the
+scala package one from the scenario classes. The core framework expects
+such a directory structure for both the scala and resources (json data)
+files.
+
+Alternatively, the TEST_HA script can be used to run Gatling tests which
+provides a minimum configuration to run the test.
+
+## How to stop
+
+Simply type CTRL+C on the window that started the environment
+and all the VMs will stop. Their state will be persisted and the next
+run will continue with the same data.
+
+## How to clean
+
+If you want to stop and cleanup all the previous state, use the 'down'
+target.
+
+```
+  $ docker-compose down
 ```
diff --git a/src/test/TEST_HA b/src/test/TEST_HA
new file mode 100755
index 0000000..ef6d4e2
--- /dev/null
+++ b/src/test/TEST_HA
@@ -0,0 +1,33 @@
+#!/bin/bash
+#
+# Example usage only-
+# 1. Locally sync plugin's scenarios to the core e2e-tests (assuming the plugin is located under gerrit's plugins
+#    directory):
+#   a. rsync -a src/test/scala/ ../../e2e-tests/src/test/scala/
+#   b. rsync -a src/test/resources/ ../../e2e-tests/src/test/resources/data/
+# 2. Change to base core e2e-tests directory to execute ./TEST_HA (this executable file) in its own terminal.
+# 3. See [1] for how to start using JAVA_OPTS below; you may leave it empty for these sbt commands. For this plugin
+#     there are some extra properties available:
+#   a. -Dcom.ericsson.gerrit.plugins.highavailability.scenarios.cluster_port to use different http port to connect
+#      to the cluster, by default port 80 is used. This option is needed to run tests locally without the need of
+#      a load balancer.
+#   b. -Dcom.ericsson.gerrit.plugins.highavailability.scenarios.http_port1 http port of the first high-availability
+#      instance, by default its 8081.
+#   c. -Dcom.ericsson.gerrit.plugins.highavailability.scenarios.http_port2 http port of the second
+#      high-availability instance, by default its 8082.
+# 13. To be able to run high-availability gatling tests without a load-balancer locally, http_cluster property
+#     needs to point to one of the high-availability instances.
+#
+# [1] https://gerrit-review.googlesource.com/Documentation/dev-e2e-tests.html#_environment_properties
+
+export GIT_HTTP_USERNAME="admin"
+export GIT_HTTP_PASSWORD="TODO"
+export JAVA_OPTS="
+"
+#-Dx=y \
+
+#sbt clean
+#sbt update
+sbt compile
+sbt "gatling:testOnly com.ericsson.gerrit.plugins.highavailability.scenarios.CloneUsingHAGerrit2"
+#sbt "gatling:lastReport"
diff --git a/src/test/docker/README.md b/src/test/docker/README.md
deleted file mode 100644
index 4604423..0000000
--- a/src/test/docker/README.md
+++ /dev/null
@@ -1,79 +0,0 @@
-# Gerrit high-availability setup example
-
-This Docker Compose project contains a simple test environment
-of two Gerrit masters in HA configuration.
-
-## How to build
-
-The project can be built using docker-compose.
-
-To build the Docker VMs:
-```
-  $ docker-compose build
-```
-
-### Building the Docker VMs using a non-default user id
-
-```
-  $ export GERRIT_UID=$(id -u)
-  $ docker-compose build --build-arg GERRIT_UID
-```
-
-Above, exporting that UID is optional and will be 1000 by default.
-Build the gerrit images this way only if the user with id 1000 on your
-host is not owned by you. For example, some corporate environments use a
-restricted 1000 user (id). In that case, the containerized application
-may fail to write towards the host (through volumes).
-
-That UID will be the one set for the containerized gerrit user. Latter's
-group will remain as default (1000). This is because groups known from
-the host need to be redefined for containers. Setting that user's group
-in the container is not necessary for writing anyway, as opposed to its
-user id. The individual gerrit user's writing permission does suffice.
-
-## How to run
-
-Use the 'up' target to startup the Docker Compose VMs.
-
-```
-  $ docker-compose up
-```
-
-## How to test
-
-Consider the
-[instructions](https://gerrit-review.googlesource.com/Documentation/dev-e2e-tests.html)
-on how to use Gerrit core's Gatling framework, to run non-core test
-scenarios such as this plugin one below:
-
-```
-  $ sbt "gatling:testOnly com.ericsson.gerrit.plugins.highavailability.scenarios.CloneUsingHAGerrit2"
-```
-
-This is a scenario that can serve as an example for how to start
-testing an HA Gerrit system. That scenario tries to clone a project
-created on gerrit 1 (port 8081) but from gerrit 2 (on 8082). The
-scenario therefore expects Gerrit HA to have properly synchronized
-the new project from 1 to 2. That project gets deleted after, here
-using HA Gerrit straight (through default http port 80).
-
-Scenario scala source files and their companion json resource ones are
-stored under the usual src/test directories. That structure follows the
-scala package one from the scenario classes. The core framework expects
-such a directory structure for both the scala and resources (json data)
-files.
-
-## How to stop
-
-Simply type CTRL+C on the window that started the environment
-and all the VMs will stop. Their state will be persisted and the next
-run will continue with the same data.
-
-## How to clean
-
-If you want to stop and cleanup all the previous state, use the 'down'
-target.
-
-```
-  $ docker-compose down
-```
diff --git a/src/test/docker/gerrit/Dockerfile b/src/test/docker/gerrit/Dockerfile
index c40d91b..3c74b10 100644
--- a/src/test/docker/gerrit/Dockerfile
+++ b/src/test/docker/gerrit/Dockerfile
@@ -1,12 +1,12 @@
-FROM gerritcodereview/gerrit:3.1.15
+FROM gerritcodereview/gerrit:3.2.10
 
-ENV GERRIT_BRANCH=stable-3.1
+ENV GERRIT_BRANCH=stable-3.2
 
-ENV GERRIT_CI_URL=https://archive-ci.gerritforge.com/job
+ENV GERRIT_CI_URL=https://gerrit-ci.gerritforge.com/job
 
 USER root
 
-RUN yum install -y iputils-ping netcat curl lsof gettext moreutils net-tools netcat inetutils-ping sudo
+RUN yum install -y iputils nmap curl lsof gettext net-tools sudo
 
 USER gerrit
 
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/GroupReindexRunnableTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/GroupReindexRunnableTest.java
index 5139a66..ce11242 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/GroupReindexRunnableTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/autoreindex/GroupReindexRunnableTest.java
@@ -194,13 +194,16 @@
   }
 
   private Optional<InternalGroup> getInternalGroup(Timestamp timestamp) {
-    AccountGroup accountGroup =
-        new AccountGroup(AccountGroup.nameKey("Test"), AccountGroup.id(1), uuid, timestamp);
     return Optional.ofNullable(
-        InternalGroup.create(
-            accountGroup,
-            ImmutableSet.<Id>builder().build(),
-            ImmutableSet.<UUID>builder().build(),
-            null));
+        InternalGroup.builder()
+            .setId(AccountGroup.Id.parse("1"))
+            .setNameKey(AccountGroup.nameKey("Test"))
+            .setOwnerGroupUUID(uuid)
+            .setVisibleToAll(true)
+            .setGroupUUID(UUID.parse("12"))
+            .setCreatedOn(timestamp)
+            .setMembers(ImmutableSet.<Id>builder().build())
+            .setSubgroups(ImmutableSet.<UUID>builder().build())
+            .build());
   }
 }
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheEvictionHandlerTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheEvictionHandlerTest.java
new file mode 100644
index 0000000..7077319
--- /dev/null
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheEvictionHandlerTest.java
@@ -0,0 +1,63 @@
+// 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.cache;
+
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+import com.ericsson.gerrit.plugins.highavailability.Configuration;
+import com.ericsson.gerrit.plugins.highavailability.forwarder.Forwarder;
+import com.google.common.cache.RemovalCause;
+import com.google.common.cache.RemovalNotification;
+import com.google.gerrit.server.config.PluginConfigFactory;
+import com.google.gerrit.server.config.SitePaths;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.concurrent.Executor;
+import org.eclipse.jgit.lib.Config;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class CacheEvictionHandlerTest {
+  @Mock private Executor executorMock;
+  @Mock private Forwarder forwarder;
+  @Mock private PluginConfigFactory pluginConfigFactoryMock;
+
+  private static final String PLUGIN_NAME = "high-availability";
+  private static final Path SITE_PATH = Paths.get("/site_path");
+  private CachePatternMatcher defaultCacheMatcher;
+
+  @Before
+  public void setUp() throws IOException {
+    when(pluginConfigFactoryMock.getGlobalPluginConfig(PLUGIN_NAME)).thenReturn(new Config());
+    defaultCacheMatcher =
+        new CachePatternMatcher(
+            new Configuration(pluginConfigFactoryMock, PLUGIN_NAME, new SitePaths(SITE_PATH)));
+  }
+
+  @Test
+  public void shouldNotPublishAccountsCacheEvictions() {
+    CacheEvictionHandler<String, String> handler =
+        new CacheEvictionHandler<>(forwarder, executorMock, PLUGIN_NAME, defaultCacheMatcher);
+    handler.onRemoval(
+        "test", "accounts", RemovalNotification.create("test", "accounts", RemovalCause.EXPLICIT));
+    verifyZeroInteractions(executorMock);
+  }
+}
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheEvictionIT.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheEvictionIT.java
index e91e2ae..180c68f 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheEvictionIT.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/CacheEvictionIT.java
@@ -26,13 +26,13 @@
 
 import com.github.tomakehurst.wiremock.junit.WireMockRule;
 import com.google.common.cache.LoadingCache;
-import com.google.gerrit.acceptance.GerritConfig;
-import com.google.gerrit.acceptance.GlobalPluginConfig;
 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.UseSsh;
+import com.google.gerrit.acceptance.config.GerritConfig;
+import com.google.gerrit.acceptance.config.GlobalPluginConfig;
 import com.google.gerrit.entities.AccountGroup;
 import com.google.inject.Inject;
 import com.google.inject.name.Named;
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 9b6e66b..caf50b9 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
@@ -38,7 +38,6 @@
     CachePatternMatcher matcher = new CachePatternMatcher(configurationMock);
     for (String cache :
         ImmutableList.of(
-            "accounts",
             "groups",
             "groups_byinclude",
             "groups_byname",
@@ -55,6 +54,7 @@
     }
     for (String cache :
         ImmutableList.of(
+            "accounts",
             "adv_bases",
             "change_kind",
             "change_notes",
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/ProjectListIT.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/ProjectListIT.java
index 22ef89e..98cdce5 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/ProjectListIT.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/cache/ProjectListIT.java
@@ -25,11 +25,11 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import com.github.tomakehurst.wiremock.junit.WireMockRule;
-import com.google.gerrit.acceptance.GlobalPluginConfig;
 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.extensions.restapi.Url;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedAwareEventBrokerTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedAwareEventBrokerTest.java
index 36cc953..cfe0475 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedAwareEventBrokerTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/ForwardedAwareEventBrokerTest.java
@@ -30,7 +30,9 @@
 
   private EventListener listenerMock;
   private ForwardedAwareEventBroker broker;
-  private Event event = new TestEvent();
+  private ForwardedAwareEventBroker brokerWithGerritInstanceId;
+  private Event event;
+  private String gerritInstanceId = "gerrit-instance-id";
 
   @Before
   public void setUp() {
@@ -38,8 +40,11 @@
     listenerMock = mock(EventListener.class);
     DynamicSet<EventListener> set = DynamicSet.emptySet();
     set.add("high-availability", listenerMock);
+    event = new TestEvent();
     PluginSetContext<EventListener> listeners = new PluginSetContext<>(set, mockMetrics);
-    broker = new ForwardedAwareEventBroker(null, listeners, null, null, null);
+    broker = new ForwardedAwareEventBroker(null, listeners, null, null, null, null);
+    brokerWithGerritInstanceId =
+        new ForwardedAwareEventBroker(null, listeners, null, null, null, gerritInstanceId);
   }
 
   @Test
@@ -58,4 +63,43 @@
     }
     verifyZeroInteractions(listenerMock);
   }
+
+  @Test
+  public void shouldNotDispatchEventWhenEventInstanceIdIsDefinedButGerritInstanceIdIsNot() {
+    event.instanceId = gerritInstanceId;
+    try {
+      broker.fireEventForUnrestrictedListeners(event);
+    } finally {
+      Context.unsetForwardedEvent();
+    }
+    verifyZeroInteractions(listenerMock);
+  }
+
+  @Test
+  public void shouldNotDispatchEventWhenGerritInstanceIdIsDefinedButEventInstanceIdIsNot() {
+    try {
+      brokerWithGerritInstanceId.fireEventForUnrestrictedListeners(event);
+    } finally {
+      Context.unsetForwardedEvent();
+    }
+    verifyZeroInteractions(listenerMock);
+  }
+
+  @Test
+  public void shouldNotDispatchEventWhenInstanceIdsAreDifferent() {
+    event.instanceId = "some-other-gerrit-instance-id";
+    try {
+      brokerWithGerritInstanceId.fireEventForUnrestrictedListeners(event);
+    } finally {
+      Context.unsetForwardedEvent();
+    }
+    verifyZeroInteractions(listenerMock);
+  }
+
+  @Test
+  public void shouldDispatchEventWhenInstanceIdsAreEqual() {
+    event.instanceId = gerritInstanceId;
+    brokerWithGerritInstanceId.fireEventForUnrestrictedListeners(event);
+    verify(listenerMock).onEvent(event);
+  }
 }
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 af4637e..5843908 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
@@ -26,11 +26,11 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import com.github.tomakehurst.wiremock.junit.WireMockRule;
-import com.google.gerrit.acceptance.GlobalPluginConfig;
 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 java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import org.apache.http.HttpStatus;