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));