Merge branch 'stable-3.4'

* stable-3.4:
  Fix merge issue for ForwardedIndexGroupHandlerTest class
  Add 'Forwarded-BatchIndex-Event' to events skipped from high-availability
  Do not forward events from high-availability
  Fix cache eviction for projects cache
  Adjust tests to reflect real life situation
  Honour index retries when indexing groups

Change-Id: I7175e2fd8da2546e11655e63316720e562b14a2d
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/CacheKeyJsonParser.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/CacheKeyJsonParser.java
index 80b2445..ef14a8e 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/CacheKeyJsonParser.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/CacheKeyJsonParser.java
@@ -33,38 +33,41 @@
   }
 
   @SuppressWarnings("cast")
-  public Object fromJson(String cacheName, Object json) {
-    Object key;
+  public Object from(String cacheName, Object cacheKeyValue) {
+    Object parsedKey;
     // Need to add a case for 'adv_bases'
     switch (cacheName) {
       case Constants.ACCOUNTS:
-        key = Account.id(jsonElement(json).getAsJsonObject().get("id").getAsInt());
+        parsedKey = Account.id(jsonElement(cacheKeyValue).getAsJsonObject().get("id").getAsInt());
         break;
       case Constants.GROUPS:
-        key = AccountGroup.id(jsonElement(json).getAsJsonObject().get("id").getAsInt());
+        parsedKey =
+            AccountGroup.id(jsonElement(cacheKeyValue).getAsJsonObject().get("id").getAsInt());
         break;
       case Constants.GROUPS_BYINCLUDE:
       case Constants.GROUPS_MEMBERS:
-        key = AccountGroup.uuid(jsonElement(json).getAsJsonObject().get("uuid").getAsString());
+        parsedKey =
+            AccountGroup.uuid(
+                jsonElement(cacheKeyValue).getAsJsonObject().get("uuid").getAsString());
         break;
       case Constants.PROJECTS:
-        key = Project.nameKey(jsonElement(json).getAsString());
+        parsedKey = Project.nameKey(nullToEmpty(cacheKeyValue));
         break;
       case Constants.PROJECT_LIST:
-        key = gson.fromJson(nullToEmpty(json).toString(), Object.class);
+        parsedKey = gson.fromJson(nullToEmpty(cacheKeyValue).toString(), Object.class);
         break;
       default:
-        if (json instanceof String) {
-          key = (String) json;
+        if (cacheKeyValue instanceof String) {
+          parsedKey = (String) cacheKeyValue;
         } else {
           try {
-            key = gson.fromJson(nullToEmpty(json).toString().trim(), String.class);
+            parsedKey = gson.fromJson(nullToEmpty(cacheKeyValue).toString().trim(), String.class);
           } catch (Exception e) {
-            key = gson.fromJson(nullToEmpty(json).toString(), Object.class);
+            parsedKey = gson.fromJson(nullToEmpty(cacheKeyValue).toString(), Object.class);
           }
         }
     }
-    return key;
+    return parsedKey;
   }
 
   private JsonElement jsonElement(Object json) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/broker/BrokerForwarder.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/broker/BrokerForwarder.java
index c833bbc..ac4c38e 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/broker/BrokerForwarder.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/broker/BrokerForwarder.java
@@ -23,6 +23,8 @@
 public abstract class BrokerForwarder {
   private static final CharSequence HIGH_AVAILABILITY_PLUGIN = "/plugins/high-availability/";
   private static final CharSequence HIGH_AVAILABILITY_FORWARDER = "Forwarded-Index-Event";
+  private static final CharSequence HIGH_AVAILABILITY_BATCH_FORWARDER =
+      "Forwarded-BatchIndex-Event";
 
   private final BrokerApiWrapper broker;
   private final Configuration cfg;
@@ -36,7 +38,8 @@
     String currentThreadName = task.getCallerThread().getName();
 
     return currentThreadName.contains(HIGH_AVAILABILITY_PLUGIN)
-        || currentThreadName.contains(HIGH_AVAILABILITY_FORWARDER);
+        || currentThreadName.contains(HIGH_AVAILABILITY_FORWARDER)
+        || currentThreadName.contains(HIGH_AVAILABILITY_BATCH_FORWARDER);
   }
 
   protected boolean send(ForwarderTask task, EventTopic eventTopic, MultiSiteEvent event) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/router/CacheEvictionEventRouter.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/router/CacheEvictionEventRouter.java
index a77e168..a44da29 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/router/CacheEvictionEventRouter.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/forwarder/router/CacheEvictionEventRouter.java
@@ -34,7 +34,7 @@
 
   @Override
   public void route(CacheEvictionEvent cacheEvictionEvent) throws CacheNotFoundException {
-    Object parsedKey = gsonParser.fromJson(cacheEvictionEvent.cacheName, cacheEvictionEvent.key);
+    Object parsedKey = gsonParser.from(cacheEvictionEvent.cacheName, cacheEvictionEvent.key);
     cacheEvictionHanlder.evict(CacheEntry.from(cacheEvictionEvent.cacheName, parsedKey));
   }
 }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/event/CacheEvictionEventRouterTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/event/CacheEvictionEventRouterTest.java
index 50507e7..6762ba2 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/event/CacheEvictionEventRouterTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/multisite/event/CacheEvictionEventRouterTest.java
@@ -16,7 +16,10 @@
 
 import static org.mockito.Mockito.verify;
 
+import com.google.gerrit.entities.Project;
+import com.google.gerrit.server.events.EventGsonProvider;
 import com.google.gson.Gson;
+import com.googlesource.gerrit.plugins.multisite.cache.Constants;
 import com.googlesource.gerrit.plugins.multisite.forwarder.CacheEntry;
 import com.googlesource.gerrit.plugins.multisite.forwarder.CacheKeyJsonParser;
 import com.googlesource.gerrit.plugins.multisite.forwarder.ForwardedCacheEvictionHandler;
@@ -32,12 +35,13 @@
 public class CacheEvictionEventRouterTest {
 
   private static final String INSTANCE_ID = "instance-id";
+  private static Gson gson = new EventGsonProvider().get();
   private CacheEvictionEventRouter router;
   @Mock private ForwardedCacheEvictionHandler cacheEvictionHandler;
 
   @Before
   public void setUp() {
-    router = new CacheEvictionEventRouter(cacheEvictionHandler, new CacheKeyJsonParser(new Gson()));
+    router = new CacheEvictionEventRouter(cacheEvictionHandler, new CacheKeyJsonParser(gson));
   }
 
   @Test
@@ -49,11 +53,22 @@
   }
 
   @Test
-  public void routerShouldSendEventsToTheAppropriateHandler_ProjectCacheEvictionWithSlash()
+  public void routerShouldSendEventsToTheAppropriateHandler_CacheEvictionWithSlash()
       throws Exception {
-    final CacheEvictionEvent event = new CacheEvictionEvent("cache", "some/project", INSTANCE_ID);
+    final CacheEvictionEvent event = new CacheEvictionEvent("cache", "some/key", INSTANCE_ID);
     router.route(event);
 
     verify(cacheEvictionHandler).evict(CacheEntry.from(event.cacheName, event.key));
   }
+
+  @Test
+  public void routerShouldSendEventsToTheAppropriateHandler_ProjectCacheEvictionWithSlash()
+      throws Exception {
+    final CacheEvictionEvent event =
+        new CacheEvictionEvent(Constants.PROJECTS, "some/project", INSTANCE_ID);
+    router.route(event);
+
+    verify(cacheEvictionHandler)
+        .evict(CacheEntry.from(event.cacheName, Project.nameKey((String) event.key)));
+  }
 }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/BrokerForwarderTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/BrokerForwarderTest.java
index 6aab497..28bf56d 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/BrokerForwarderTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/BrokerForwarderTest.java
@@ -40,6 +40,7 @@
 public class BrokerForwarderTest {
   private static final String HIGH_AVAILABILITY_PLUGIN = "/plugins/high-availability/";
   private static final String HIGH_AVAILABILITY_FORWARDED = "Forwarded-Index-Event";
+  private static final String HIGH_AVAILABILITY_BATCH_FORWARDED = "Forwarded-BatchIndex-Event";
   private static final long TEST_TIMEOUT_SEC = 5L;
 
   @Mock private BrokerApiWrapper brokerMock;
@@ -108,6 +109,13 @@
     verifyZeroInteractions(brokerMock);
   }
 
+  @Test
+  public void shouldSkipEventFromHighAvailabilityPluginBatchForwardedThread() {
+    brokerForwarder.send(newForwarderTask(HIGH_AVAILABILITY_BATCH_FORWARDED), testTopic, testEvent);
+
+    verifyZeroInteractions(brokerMock);
+  }
+
   private ForwarderTask newForwarderTask(String threadName) {
     try {
       return executor
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/CacheKeyJsonParserTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/CacheKeyJsonParserTest.java
index 7efd4dd..e42b4e5 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/CacheKeyJsonParserTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/CacheKeyJsonParserTest.java
@@ -34,34 +34,34 @@
   public void accountIDParse() {
     Account.Id accountId = Account.id(1);
     String json = gson.toJson(accountId);
-    assertThat(accountId).isEqualTo(gsonParser.fromJson(Constants.ACCOUNTS, json));
+    assertThat(accountId).isEqualTo(gsonParser.from(Constants.ACCOUNTS, json));
   }
 
   @Test
   public void accountGroupIDParse() {
     AccountGroup.Id accountGroupId = AccountGroup.id(1);
     String json = gson.toJson(accountGroupId);
-    assertThat(accountGroupId).isEqualTo(gsonParser.fromJson(Constants.GROUPS, json));
+    assertThat(accountGroupId).isEqualTo(gsonParser.from(Constants.GROUPS, json));
   }
 
   @Test
   public void accountGroupUUIDParse() {
     AccountGroup.UUID accountGroupUuid = AccountGroup.uuid("abc123");
     String json = gson.toJson(accountGroupUuid);
-    assertThat(accountGroupUuid).isEqualTo(gsonParser.fromJson(Constants.GROUPS_BYINCLUDE, json));
+    assertThat(accountGroupUuid).isEqualTo(gsonParser.from(Constants.GROUPS_BYINCLUDE, json));
   }
 
   @Test
   public void projectNameKeyParse() {
-    Project.NameKey name = Project.nameKey("foo");
-    String json = gson.toJson(name);
-    assertThat(name).isEqualTo(gsonParser.fromJson(Constants.PROJECTS, json));
+    String projectNameString = "foo";
+    Project.NameKey projectNameKey = Project.nameKey(projectNameString);
+    assertThat(projectNameKey).isEqualTo(gsonParser.from(Constants.PROJECTS, projectNameString));
   }
 
   @Test
   public void stringParse() {
     String key = "key";
-    assertThat(key).isEqualTo(gsonParser.fromJson("any-cache-with-string-key", key));
+    assertThat(key).isEqualTo(gsonParser.from("any-cache-with-string-key", key));
   }
 
   @Test
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/ForwardedCacheEvictionHandlerIT.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/ForwardedCacheEvictionHandlerIT.java
index b3d46cf..75596ed 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/ForwardedCacheEvictionHandlerIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/multisite/forwarder/ForwardedCacheEvictionHandlerIT.java
@@ -23,6 +23,8 @@
 import com.google.gerrit.acceptance.LightweightPluginDaemonTest;
 import com.google.gerrit.acceptance.TestPlugin;
 import com.google.gerrit.acceptance.config.GerritConfig;
+import com.google.gerrit.entities.Project;
+import com.google.gerrit.extensions.api.projects.ProjectInput;
 import com.google.gerrit.extensions.registration.DynamicSet;
 import com.google.gerrit.extensions.registration.RegistrationHandle;
 import com.google.gerrit.server.cache.CacheRemovalListener;
@@ -125,10 +127,33 @@
   @GerritConfig(name = "gerrit.instanceId", value = "testInstanceId")
   public void shouldEvictProjectCache() throws Exception {
     objectUnderTest.route(
-        new CacheEvictionEvent(ProjectCacheImpl.CACHE_NAME, gson.toJson(project), "instance-id"));
+        new CacheEvictionEvent(ProjectCacheImpl.CACHE_NAME, project.get(), "instance-id"));
     evictionsCacheTracker.waitForExpectedEvictions();
 
     assertThat(evictionsCacheTracker.trackedEvictionsFor(ProjectCacheImpl.CACHE_NAME))
         .contains(project);
   }
+
+  @Test
+  @GerritConfig(name = "gerrit.instanceId", value = "instance-id")
+  public void shouldEvictProjectCacheWithSlash() throws Exception {
+    ProjectInput in = new ProjectInput();
+    in.name = name("my/project");
+    gApi.projects().create(in);
+    Project.NameKey projectNameKey = Project.nameKey(in.name);
+
+    restartCacheEvictionsTracking();
+
+    objectUnderTest.route(
+        new CacheEvictionEvent(ProjectCacheImpl.CACHE_NAME, projectNameKey.get(), "instance-id"));
+
+    evictionsCacheTracker.waitForExpectedEvictions();
+    assertThat(evictionsCacheTracker.trackedEvictionsFor(ProjectCacheImpl.CACHE_NAME))
+        .contains(projectNameKey);
+  }
+
+  private void restartCacheEvictionsTracking() {
+    stopTrackingCacheEvictions();
+    startTrackingCacheEvictions();
+  }
 }