JGroupsForwarder index: carry metaSha/targetSha through IndexChange command

The IndexChange command was not carrying metaSha and targetSha from
IndexEvent, so CommandProcessorImpl passed Optional.empty() to
ForwardedIndexChangeHandler. This bypassed the isChangeUpToDate()
staleness guard, which relies on metaSha to verify that the meta-ref
object is visible through JGit before accepting the index result as
up to date.

Extend IndexChange and its subclasses to carry targetSha and metaSha
from IndexEvent. CommandProcessorImpl reconstructs IndexEvent from
those fields and passes it to the handler, enabling Failsafe to retry
indexing until the meta-ref becomes visible.

Change-Id: Ib133f58613542e34a81f5b43b8cada1918ca538f
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/CommandProcessorImpl.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/CommandProcessorImpl.java
index cadfaea..635ef4f 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/CommandProcessorImpl.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/CommandProcessorImpl.java
@@ -23,6 +23,7 @@
 import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwardedIndexChangeHandler;
 import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwardedIndexingHandler.Operation;
 import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwardedProjectListUpdateHandler;
+import com.ericsson.gerrit.plugins.highavailability.forwarder.IndexEvent;
 import com.ericsson.gerrit.plugins.highavailability.forwarder.ProcessorMetrics;
 import com.ericsson.gerrit.plugins.highavailability.forwarder.ProcessorMetricsRegistry;
 import com.google.common.annotations.VisibleForTesting;
@@ -81,7 +82,7 @@
         try {
           ForwardedIndexChangeHandler handler =
               indexChange.isBatch() ? indexBatchChangeHandler : indexChangeHandler;
-          handler.index(indexChange.getId(), op, Optional.empty());
+          handler.index(indexChange.getId(), op, Optional.of(toIndexEvent(indexChange)));
           log.atFine().log(
               "Change index %s on change %s done", op.name().toLowerCase(), indexChange.getId());
         } catch (Exception e) {
@@ -140,4 +141,12 @@
       throw new IllegalArgumentException("Unknown type of IndexChange command " + cmd.getClass());
     }
   }
+
+  private static IndexEvent toIndexEvent(IndexChange cmd) {
+    IndexEvent e = new IndexEvent();
+    e.eventCreatedOn = cmd.eventCreatedOn;
+    e.targetSha = cmd.targetSha;
+    e.metaSha = cmd.metaSha;
+    return e;
+  }
 }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/IndexChange.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/IndexChange.java
index df79eca..c176c50 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/IndexChange.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/commands/IndexChange.java
@@ -15,20 +15,24 @@
 package com.ericsson.gerrit.plugins.highavailability.forwarder.commands;
 
 import com.ericsson.gerrit.plugins.highavailability.forwarder.EventType;
+import com.ericsson.gerrit.plugins.highavailability.forwarder.IndexEvent;
 import com.google.common.base.Strings;
-import java.time.Instant;
 
 public abstract class IndexChange extends Command {
   private final String projectName;
   private final int id;
   private final boolean batchMode;
+  public final String targetSha;
+  public final String metaSha;
 
   protected IndexChange(
-      EventType type, String projectName, int id, boolean batchMode, Instant eventCreatedOn) {
-    super(type, eventCreatedOn);
+      EventType type, String projectName, int id, boolean batchMode, IndexEvent indexEvent) {
+    super(type, indexEvent.eventCreatedOn);
     this.projectName = projectName;
     this.id = id;
     this.batchMode = batchMode;
+    this.targetSha = indexEvent.targetSha;
+    this.metaSha = indexEvent.metaSha;
   }
 
   public String getId() {
@@ -42,24 +46,24 @@
   public static class Update extends IndexChange {
     static final EventType TYPE = EventType.INDEX_CHANGE_UPDATE;
 
-    public Update(String projectName, int id, Instant eventCreatedOn) {
-      super(TYPE, projectName, id, false, eventCreatedOn);
+    public Update(String projectName, int id, IndexEvent indexEvent) {
+      super(TYPE, projectName, id, false, indexEvent);
     }
   }
 
   public static class BatchUpdate extends IndexChange {
     static final EventType TYPE = EventType.INDEX_CHANGE_UPDATE_BATCH;
 
-    public BatchUpdate(String projectName, int id, Instant eventCreatedOn) {
-      super(TYPE, projectName, id, true, eventCreatedOn);
+    public BatchUpdate(String projectName, int id, IndexEvent indexEvent) {
+      super(TYPE, projectName, id, true, indexEvent);
     }
   }
 
   public static class Delete extends IndexChange {
     static final EventType TYPE = EventType.INDEX_CHANGE_DELETION;
 
-    public Delete(String projectName, int id, Instant eventCreatedOn) {
-      super(TYPE, projectName, id, false, eventCreatedOn);
+    public Delete(String projectName, int id, IndexEvent indexEvent) {
+      super(TYPE, projectName, id, false, indexEvent);
     }
   }
 }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/JGroupsForwarder.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/JGroupsForwarder.java
index 225738f..a66dd41 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/JGroupsForwarder.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/JGroupsForwarder.java
@@ -87,19 +87,19 @@
   @Override
   public CompletableFuture<Result> indexChange(
       String projectName, int changeId, IndexEvent indexEvent) {
-    return execute(new IndexChange.Update(projectName, changeId, indexEvent.eventCreatedOn));
+    return execute(new IndexChange.Update(projectName, changeId, indexEvent));
   }
 
   @Override
   public CompletableFuture<Result> batchIndexChange(
       String projectName, int changeId, IndexEvent indexEvent) {
-    return execute(new IndexChange.BatchUpdate(projectName, changeId, indexEvent.eventCreatedOn));
+    return execute(new IndexChange.BatchUpdate(projectName, changeId, indexEvent));
   }
 
   @Override
   public CompletableFuture<Result> deleteChangeFromIndex(
       String projectName, int changeId, IndexEvent indexEvent) {
-    return execute(new IndexChange.Delete(projectName, changeId, indexEvent.eventCreatedOn));
+    return execute(new IndexChange.Delete(projectName, changeId, indexEvent));
   }
 
   @Override
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/MessageProcessorTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/MessageProcessorTest.java
index bca7801..39493a1 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/MessageProcessorTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/forwarder/jgroups/MessageProcessorTest.java
@@ -16,6 +16,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
@@ -31,6 +32,7 @@
 import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwardedIndexChangeHandler;
 import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwardedIndexingHandler.Operation;
 import com.ericsson.gerrit.plugins.highavailability.forwarder.ForwardedProjectListUpdateHandler;
+import com.ericsson.gerrit.plugins.highavailability.forwarder.IndexEvent;
 import com.ericsson.gerrit.plugins.highavailability.forwarder.ProcessorMetrics;
 import com.ericsson.gerrit.plugins.highavailability.forwarder.ProcessorMetricsRegistry;
 import com.ericsson.gerrit.plugins.highavailability.forwarder.commands.AddToProjectList;
@@ -126,10 +128,10 @@
     String PROJECT = "foo";
     int CHANGE_ID = 100;
 
-    IndexChange.Update cmd = new IndexChange.Update(PROJECT, CHANGE_ID, Instant.now());
+    IndexChange.Update cmd = new IndexChange.Update(PROJECT, CHANGE_ID, new IndexEvent());
     assertThat(processor.handle(new ObjectMessage(null, gson.toJson(cmd)))).isEqualTo(true);
     verify(indexChangeHandler, times(1))
-        .index(PROJECT + "~" + Change.id(CHANGE_ID), Operation.INDEX, Optional.empty());
+        .index(eq(PROJECT + "~" + Change.id(CHANGE_ID)), eq(Operation.INDEX), any());
     verifyOtherHandlersNotUsed(indexChangeHandler);
   }
 
@@ -138,10 +140,10 @@
     String PROJECT = "foo";
     int CHANGE_ID = 100;
 
-    IndexChange.BatchUpdate cmd = new IndexChange.BatchUpdate(PROJECT, CHANGE_ID, Instant.now());
+    IndexChange.BatchUpdate cmd = new IndexChange.BatchUpdate(PROJECT, CHANGE_ID, new IndexEvent());
     assertThat(processor.handle(new ObjectMessage(null, gson.toJson(cmd)))).isEqualTo(true);
     verify(indexBatchChangeHandler, times(1))
-        .index(PROJECT + "~" + Change.id(CHANGE_ID), Operation.INDEX, Optional.empty());
+        .index(eq(PROJECT + "~" + Change.id(CHANGE_ID)), eq(Operation.INDEX), any());
     verifyOtherHandlersNotUsed(indexBatchChangeHandler);
   }
 
@@ -150,10 +152,10 @@
     String PROJECT = "foo";
     int CHANGE_ID = 100;
 
-    IndexChange.Delete cmd = new IndexChange.Delete(PROJECT, CHANGE_ID, Instant.now());
+    IndexChange.Delete cmd = new IndexChange.Delete(PROJECT, CHANGE_ID, new IndexEvent());
     assertThat(processor.handle(new ObjectMessage(null, gson.toJson(cmd)))).isEqualTo(true);
     verify(indexChangeHandler, times(1))
-        .index(PROJECT + "~" + Change.id(CHANGE_ID), Operation.DELETE, Optional.empty());
+        .index(eq(PROJECT + "~" + Change.id(CHANGE_ID)), eq(Operation.DELETE), any());
     verifyOtherHandlersNotUsed(indexChangeHandler);
   }