Merge "Reload latest SHA1 from local when filtering RemoteRefUpdate" into stable-3.4
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/MultisiteReplicationPushFilter.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/MultisiteReplicationPushFilter.java
index 98f4897..c9300c8 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/MultisiteReplicationPushFilter.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/MultisiteReplicationPushFilter.java
@@ -27,6 +27,7 @@
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Optional;
 import java.util.Random;
 import java.util.Set;
 import java.util.stream.Collectors;
@@ -66,19 +67,23 @@
         gitRepositoryManager.openRepository(Project.nameKey(projectName))) {
       List<RemoteRefUpdate> filteredRefUpdates =
           remoteUpdatesList.stream()
-              .filter(
+              .map(
                   refUpdate -> {
-                    boolean refUpToDate = isUpToDateWithRetry(projectName, repository, refUpdate);
-                    if (!refUpToDate) {
+                    Optional<RemoteRefUpdate> updatedRefUpdate =
+                        isUpToDateWithRetry(projectName, repository, refUpdate);
+                    if (!updatedRefUpdate.isPresent()) {
                       repLog.warn(
-                          "{} is not up-to-date with the shared-refdb and thus will NOT BE replicated",
+                          "{} is not up-to-date with the shared-refdb and thus will NOT BE"
+                              + " replicated",
                           refUpdate);
                       if (refUpdate.getSrcRef().endsWith(REF_META_SUFFIX)) {
                         outdatedChanges.add(getRootChangeRefPrefix(refUpdate.getSrcRef()));
                       }
                     }
-                    return refUpToDate;
+                    return updatedRefUpdate;
                   })
+              .filter(Optional::isPresent)
+              .map(Optional::get)
               .collect(Collectors.toList());
 
       return filteredRefUpdates.stream()
@@ -102,37 +107,56 @@
     }
   }
 
-  private boolean isUpToDateWithRetry(
+  private Optional<RemoteRefUpdate> isUpToDateWithRetry(
       String projectName, Repository repository, RemoteRefUpdate refUpdate) {
     String ref = refUpdate.getSrcRef();
     try {
       if (sharedRefDb.isUpToDate(
           Project.nameKey(projectName),
           new ObjectIdRef.Unpeeled(Ref.Storage.NETWORK, ref, refUpdate.getNewObjectId()))) {
-        return true;
+        return Optional.of(refUpdate);
       }
 
       randomSleepForMitigatingConditionWhereLocalRefHaveJustBeenChanged(
           projectName, refUpdate, ref);
 
+      ObjectId reloadedNewObjectId = getNotNullExactRef(repository, ref);
+      RemoteRefUpdate refUpdateReloaded =
+          newRemoteRefUpdateWithObjectId(repository, refUpdate, reloadedNewObjectId);
       return sharedRefDb.isUpToDate(
-          Project.nameKey(projectName),
-          new ObjectIdRef.Unpeeled(Ref.Storage.NETWORK, ref, getNotNullExactRef(repository, ref)));
+              Project.nameKey(projectName),
+              new ObjectIdRef.Unpeeled(
+                  Ref.Storage.NETWORK, ref, refUpdateReloaded.getNewObjectId()))
+          ? Optional.of(refUpdateReloaded)
+          : Optional.empty();
     } catch (GlobalRefDbLockException gle) {
       String message =
           String.format("%s is locked on shared-refdb and thus will NOT BE replicated", ref);
       repLog.error(message);
       logger.atSevere().withCause(gle).log(message);
-      return false;
+      return Optional.empty();
     } catch (IOException ioe) {
       String message =
           String.format("Error while extracting ref '%s' for project '%s'", ref, projectName);
       repLog.error(message);
       logger.atSevere().withCause(ioe).log(message);
-      return false;
+      return Optional.empty();
     }
   }
 
+  private RemoteRefUpdate newRemoteRefUpdateWithObjectId(
+      Repository localDb, RemoteRefUpdate refUpdate, ObjectId reloadedNewObjectId)
+      throws IOException {
+    return new RemoteRefUpdate(
+        localDb,
+        refUpdate.getSrcRef(),
+        reloadedNewObjectId,
+        refUpdate.getRemoteName(),
+        refUpdate.isForceUpdate(),
+        null,
+        refUpdate.getExpectedOldObjectId());
+  }
+
   private void randomSleepForMitigatingConditionWhereLocalRefHaveJustBeenChanged(
       String projectName, RemoteRefUpdate refUpdate, String ref) {
     int randomSleepTimeMsec =
@@ -140,7 +164,8 @@
             + new Random().nextInt(RANDOM_WAIT_BEFORE_RELOAD_LOCAL_VERSION_MS);
     repLog.debug(
         String.format(
-            "'%s' is not up-to-date for project '%s' [local='%s']. Reload local ref in '%d ms' and re-check",
+            "'%s' is not up-to-date for project '%s' [local='%s']. Reload local ref in '%d ms' and"
+                + " re-check",
             ref, projectName, refUpdate.getNewObjectId(), randomSleepTimeMsec));
     try {
       Thread.sleep(randomSleepTimeMsec);
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/MultisiteReplicationPushFilterTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/MultisiteReplicationPushFilterTest.java
index 5c3f8f0..b45e1fb 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/MultisiteReplicationPushFilterTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/MultisiteReplicationPushFilterTest.java
@@ -102,7 +102,10 @@
 
   @Test
   public void shouldLoadLocalVersionAndNotFilter() throws Exception {
-    RemoteRefUpdate temporaryOutdated = refUpdate("refs/heads/temporaryOutdated");
+    String refName = "refs/heads/temporaryOutdated";
+    RemoteRefUpdate temporaryOutdated = refUpdate(refName);
+    ObjectId latestObjectId = repo.getRepository().exactRef(refName).getObjectId();
+
     List<RemoteRefUpdate> refUpdates = Collections.singletonList(temporaryOutdated);
     doReturn(false).doReturn(true).when(sharedRefDatabaseMock).isUpToDate(eq(projectName), any());
 
@@ -110,7 +113,9 @@
         new MultisiteReplicationPushFilter(sharedRefDatabaseMock, gitRepositoryManager);
     List<RemoteRefUpdate> filteredRefUpdates = pushFilter.filter(project, refUpdates);
 
-    assertThat(filteredRefUpdates).containsExactly(temporaryOutdated);
+    assertThat(filteredRefUpdates).hasSize(1);
+    assertThat(filteredRefUpdates.get(0).getNewObjectId()).isEqualTo(latestObjectId);
+
     verify(sharedRefDatabaseMock, times(2)).isUpToDate(any(), any());
   }