Merge branch 'stable-2.16' into stable-3.0

* stable-2.16:
  Fix shared-ref up to date check for deleted branches

Change-Id: I60d162294291ab8d0aea09828c25658218ee2ae2
diff --git a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/RefUpdateValidator.java b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/RefUpdateValidator.java
index dec6ae4..15e8602 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/RefUpdateValidator.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/multisite/validation/RefUpdateValidator.java
@@ -149,8 +149,7 @@
     }
   }
 
-  protected RefPair compareAndGetLatestLocalRef(
-      RefPair refPair, CloseableSet<AutoCloseable> locks)
+  protected RefPair compareAndGetLatestLocalRef(RefPair refPair, CloseableSet<AutoCloseable> locks)
       throws SharedLockException, OutOfSyncException, IOException {
     String refName = refPair.getName();
     EnforcePolicy refEnforcementPolicy = refEnforcement.getPolicy(projectName, refName);
@@ -163,12 +162,11 @@
         () -> sharedRefDb.lockRef(projectName, refName));
 
     RefPair latestRefPair = getLatestLocalRef(refPair);
-    boolean isInSync =
-        (latestRefPair.compareRef.getObjectId().equals(ObjectId.zeroId()))
-            ? !sharedRefDb.exists(projectName, refName)
-            : sharedRefDb.isUpToDate(projectName, latestRefPair.compareRef);
+    if (sharedRefDb.isUpToDate(projectName, latestRefPair.compareRef)) {
+      return latestRefPair;
+    }
 
-    if (!isInSync) {
+    if (isNullRef(latestRefPair.compareRef) || sharedRefDb.exists(projectName, refName)) {
       validationMetrics.incrementSplitBrainPrevention();
 
       softFailBasedOnEnforcement(
@@ -178,6 +176,10 @@
     return latestRefPair;
   }
 
+  private boolean isNullRef(Ref ref) {
+    return ref.getObjectId().equals(ObjectId.zeroId());
+  }
+
   private RefPair getLatestLocalRef(RefPair refPair) throws IOException {
     Ref latestRef = refDb.exactRef(refPair.getName());
     return new RefPair(
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/MultiSiteBatchRefUpdateTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/MultiSiteBatchRefUpdateTest.java
index 9b8b562..9acedef 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/MultiSiteBatchRefUpdateTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/MultiSiteBatchRefUpdateTest.java
@@ -126,7 +126,7 @@
   @Test
   public void executeAndFailsWithExceptions() throws IOException {
     setMockRequiredReturnValues();
-
+    doReturn(true).when(sharedRefDb).exists(A_TEST_PROJECT_NAME, A_TEST_REF_NAME);
     doReturn(false).when(sharedRefDb).isUpToDate(A_TEST_PROJECT_NAME, oldRef);
     try {
       multiSiteRefUpdate.execute(revWalk, progressMonitor, Collections.emptyList());
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/RefUpdateValidatorTest.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/RefUpdateValidatorTest.java
index d95860c..6fa7ed4 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/RefUpdateValidatorTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/RefUpdateValidatorTest.java
@@ -135,6 +135,7 @@
   @Test(expected = OutOfSyncException.class)
   public void validationShouldFailWhenLocalRefDbIsNotUpToDate() throws Exception {
     lenient().doReturn(true).when(sharedRefDb).isUpToDate(anyString(), any(Ref.class));
+    doReturn(true).when(sharedRefDb).exists(A_TEST_PROJECT_NAME, refName);
     doReturn(false).when(sharedRefDb).isUpToDate(A_TEST_PROJECT_NAME, localRef);
 
     refUpdateValidator.executeRefUpdate(refUpdate, () -> RefUpdate.Result.NEW);
diff --git a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/zookeeper/ZkSharedRefDatabaseIT.java b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/zookeeper/ZkSharedRefDatabaseIT.java
index 03f5c49..cfa5476 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/zookeeper/ZkSharedRefDatabaseIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/multisite/validation/dfsrefdb/zookeeper/ZkSharedRefDatabaseIT.java
@@ -16,6 +16,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
 import com.google.gerrit.acceptance.AbstractDaemonTest;
 import com.google.gerrit.metrics.DisabledMetricMaker;
@@ -138,6 +139,31 @@
     assertFalse(existsDataInZkForCommand(aNewCreate));
   }
 
+  @Test
+  public void shouldBeSuccessfulWhenRefIsRecreated() throws Exception {
+    ObjectId commitObjectIdOne = commitBuilder().add("test_file1.txt", "A").create().getId();
+    ObjectId commitObjectIdTwo = commitBuilder().add("test_file1.txt", "B").create().getId();
+
+    ReceiveCommand firstCommand =
+        new ReceiveCommand(ObjectId.zeroId(), commitObjectIdOne, A_TEST_REF_NAME);
+
+    ReceiveCommand deleteCommand =
+        new ReceiveCommand(commitObjectIdOne, ObjectId.zeroId(), A_TEST_REF_NAME, Type.DELETE);
+
+    ReceiveCommand secondCommand =
+        new ReceiveCommand(ObjectId.zeroId(), commitObjectIdTwo, A_TEST_REF_NAME);
+
+    InMemoryRepository repository = testRepo.getRepository();
+    try (RevWalk rw = new RevWalk(repository)) {
+
+      newBatchRefUpdate(repository, firstCommand).execute(rw, NullProgressMonitor.INSTANCE);
+      newBatchRefUpdate(repository, deleteCommand).execute(rw, NullProgressMonitor.INSTANCE);
+      newBatchRefUpdate(repository, secondCommand).execute(rw, NullProgressMonitor.INSTANCE);
+    }
+
+    assertTrue(existsDataInZkForCommand(secondCommand));
+  }
+
   private boolean existsDataInZkForCommand(ReceiveCommand firstCommand) throws Exception {
     return zkSharedRefDatabase.exists(A_TEST_PROJECT_NAME, firstCommand.getRefName());
   }