Fix the create/delete of ref-specs in FetchOne delta

When adding a ref-update to a ref-delete on FetchOne or
ref-delete to an existing ref-update, the existing operation
should be removed and only the last one should take effect.

Change-Id: I1d2a3a492db0a1b45bfbdf0ce89030656ebbb338
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/FetchOne.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/FetchOne.java
index 5e7fda2..939a05b 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/FetchOne.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/FetchOne.java
@@ -228,14 +228,16 @@
       // set may risk to have both update and delete for the same
       // ref, which would be an issue: the delta is an unordered set
       // and executing updates and deletes for the same ref may have
-      // unexpected results, depending on which one you execute firt.
-      //
-      // Delete any previous ref-spec as delete or update for the same
-      // refname so that the subsequent addition will make sure that
-      // there is only one operation per refName.
-      delta.remove(ref);
+      // unexpected results, depending on which one you execute first.
+
+      // Delete any previous ref-spec as delete
+      delta.remove(FetchRefSpec.fromRef(":" + ref.refName()));
+
+      // Delete any previous ref-spec as update
       delta.remove(FetchRefSpec.fromRef(ref.refName()));
 
+      // Add the new ref as-is for making sure that
+      // there is only one operation per refName.
       delta.add(ref);
       repLog.trace("[{}] Added ref {} for replication from {}", taskIdHex, ref, uri);
     }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/FetchOneTest.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/FetchOneTest.java
index 73715d6..6ce3dbe 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/FetchOneTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/FetchOneTest.java
@@ -70,6 +70,7 @@
   private final String TEST_PROJECT_NAME = "FetchOneTest";
   private final Project.NameKey PROJECT_NAME = Project.NameKey.parse(TEST_PROJECT_NAME);
   private final String TEST_REF = "refs/heads/refForReplicationTask";
+  private final String TEST_DELETE_REF = ":" + TEST_REF;
   private final FetchRefSpec TEST_REF_SPEC = FetchRefSpec.fromRef(TEST_REF);
   private final String URI_PATTERN = "http://test.com/" + TEST_PROJECT_NAME + ".git";
   private final TestMetricMaker testMetricMaker = new TestMetricMaker();
@@ -178,6 +179,26 @@
   }
 
   @Test
+  public void shouldDeleteRefWhenAddingDeleteRefSpec() throws IOException {
+    setupRemoteConfigMock(List.of(ALL_REFS_SPEC));
+    objectUnderTest.addRefs(refSpecsSetOf(TEST_REF));
+    objectUnderTest.addRefs(refSpecsSetOf(TEST_DELETE_REF));
+
+    assertThat(objectUnderTest.getFetchRefSpecs())
+        .isEqualTo(List.of(FetchRefSpec.fromRef(TEST_DELETE_REF)));
+  }
+
+  @Test
+  public void shouldAddRefWhenAddingRefSpecToDeleteRefSpec() throws IOException {
+    setupRemoteConfigMock(List.of(ALL_REFS_SPEC));
+    objectUnderTest.addRefs(refSpecsSetOf(TEST_DELETE_REF));
+    objectUnderTest.addRefs(refSpecsSetOf(TEST_REF));
+
+    assertThat(objectUnderTest.getFetchRefSpecs())
+        .isEqualTo(List.of(FetchRefSpec.fromRef(TEST_REF + ":" + TEST_REF)));
+  }
+
+  @Test
   public void shouldReturnExistingStates() {
     assertThat(createTestStates(TEST_REF_SPEC, 1))
         .isEqualTo(objectUnderTest.getStates().get(TEST_REF_SPEC));