Listen to GitBatchRefUpdateListener for a set of events When replicating a set of events, prefer to listen to a group of ref-update events together, so that they can be sorted by passing the /meta refs at the end of the calls. Bug: Issue 16608 Change-Id: I71d6d763e46ea143bd0eef227991da9b15a82554
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationModule.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationModule.java index cd19be4..08a402e 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationModule.java +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationModule.java
@@ -19,7 +19,7 @@ import com.google.common.eventbus.EventBus; import com.google.gerrit.extensions.annotations.Exports; import com.google.gerrit.extensions.config.CapabilityDefinition; -import com.google.gerrit.extensions.events.GitReferenceUpdatedListener; +import com.google.gerrit.extensions.events.GitBatchRefUpdateListener; import com.google.gerrit.extensions.events.HeadUpdatedListener; import com.google.gerrit.extensions.events.LifecycleListener; import com.google.gerrit.extensions.events.ProjectDeletedListener; @@ -123,7 +123,7 @@ .annotatedWith(UniqueAnnotations.create()) .to(ReplicationQueue.class); - DynamicSet.bind(binder(), GitReferenceUpdatedListener.class).to(ReplicationQueue.class); + DynamicSet.bind(binder(), GitBatchRefUpdateListener.class).to(ReplicationQueue.class); bind(ConfigParser.class).to(SourceConfigParser.class).in(Scopes.SINGLETON);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/ReplicationQueue.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/ReplicationQueue.java index f5b27ee..990c82c 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/ReplicationQueue.java +++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/ReplicationQueue.java
@@ -20,7 +20,7 @@ import com.google.gerrit.entities.Project; import com.google.gerrit.entities.Project.NameKey; import com.google.gerrit.entities.RefNames; -import com.google.gerrit.extensions.events.GitReferenceUpdatedListener; +import com.google.gerrit.extensions.events.GitBatchRefUpdateListener; import com.google.gerrit.extensions.events.HeadUpdatedListener; import com.google.gerrit.extensions.events.LifecycleListener; import com.google.gerrit.extensions.events.ProjectDeletedListener; @@ -65,7 +65,7 @@ public class ReplicationQueue implements ObservableQueue, LifecycleListener, - GitReferenceUpdatedListener, + GitBatchRefUpdateListener, ProjectDeletedListener, HeadUpdatedListener { @@ -147,17 +147,24 @@ } @Override - public void onGitReferenceUpdated(GitReferenceUpdatedListener.Event event) { - if (isRefToBeReplicated(event.getRefName())) { - repLog.info( - "Ref event received: {} on project {}:{} - {} => {}", - refUpdateType(event), - event.getProjectName(), - event.getRefName(), - event.getOldObjectId(), - event.getNewObjectId()); - fire(ReferenceUpdatedEvent.from(event)); - } + public void onGitBatchRefUpdate(GitBatchRefUpdateListener.Event event) { + event.getUpdatedRefs().stream() + .sorted(ReplicationQueue::sortByMetaRefAsLast) + .forEachOrdered( + updateRef -> { + String refName = updateRef.getRefName(); + + if (isRefToBeReplicated(refName)) { + repLog.info( + "Ref event received: {} on project {}:{} - {} => {}", + refUpdateType(updateRef), + event.getProjectName(), + refName, + updateRef.getOldObjectId(), + updateRef.getNewObjectId()); + fire(ReferenceUpdatedEvent.from(event.getProjectName(), updateRef)); + } + }); } @Override @@ -170,11 +177,17 @@ source.getApis().forEach(apiUrl -> source.scheduleDeleteProject(apiUrl, project))); } - private static String refUpdateType(GitReferenceUpdatedListener.Event event) { - String forcedPrefix = event.isNonFastForward() ? "FORCED " : " "; - if (event.isCreate()) { + private static int sortByMetaRefAsLast(UpdatedRef a, @SuppressWarnings("unused") UpdatedRef b) { + repLog.info("sortByMetaRefAsLast(" + a.getRefName() + " <=> " + b.getRefName()); + return Boolean.compare( + RefNames.isNoteDbMetaRef(a.getRefName()), RefNames.isNoteDbMetaRef(b.getRefName())); + } + + private static String refUpdateType(UpdatedRef updateRef) { + String forcedPrefix = updateRef.isNonFastForward() ? "FORCED " : " "; + if (updateRef.isCreate()) { return forcedPrefix + "CREATE"; - } else if (event.isDelete()) { + } else if (updateRef.isDelete()) { return forcedPrefix + "DELETE"; } else { return forcedPrefix + "UPDATE"; @@ -518,12 +531,12 @@ projectName, refName, objectId, isDelete); } - static ReferenceUpdatedEvent from(GitReferenceUpdatedListener.Event event) { + static ReferenceUpdatedEvent from(String projectName, UpdatedRef updateRef) { return ReferenceUpdatedEvent.create( - event.getProjectName(), - event.getRefName(), - ObjectId.fromString(event.getNewObjectId()), - event.isDelete()); + projectName, + updateRef.getRefName(), + ObjectId.fromString(updateRef.getNewObjectId()), + updateRef.isDelete()); } public abstract String projectName();
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/FakeGitReferenceUpdatedEvent.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/FakeGitReferenceUpdatedEvent.java index 43331dc..69549aa 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/FakeGitReferenceUpdatedEvent.java +++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/FakeGitReferenceUpdatedEvent.java
@@ -17,10 +17,13 @@ import com.google.gerrit.entities.Project; import com.google.gerrit.extensions.api.changes.NotifyHandling; import com.google.gerrit.extensions.common.AccountInfo; -import com.google.gerrit.extensions.events.GitReferenceUpdatedListener; +import com.google.gerrit.extensions.events.GitBatchRefUpdateListener; +import com.google.gerrit.extensions.events.GitBatchRefUpdateListener.UpdatedRef; +import java.util.Set; +import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.transport.ReceiveCommand; -public class FakeGitReferenceUpdatedEvent implements GitReferenceUpdatedListener.Event { +public class FakeGitReferenceUpdatedEvent implements GitBatchRefUpdateListener.Event { private final String projectName; private final String ref; private final String oldObjectId; @@ -46,36 +49,6 @@ } @Override - public String getRefName() { - return ref; - } - - @Override - public String getOldObjectId() { - return oldObjectId; - } - - @Override - public String getNewObjectId() { - return newObjectId; - } - - @Override - public boolean isCreate() { - return type == ReceiveCommand.Type.CREATE; - } - - @Override - public boolean isDelete() { - return type == ReceiveCommand.Type.DELETE; - } - - @Override - public boolean isNonFastForward() { - return type == ReceiveCommand.Type.UPDATE_NONFASTFORWARD; - } - - @Override public AccountInfo getUpdater() { return null; } @@ -91,4 +64,46 @@ public NotifyHandling getNotify() { return NotifyHandling.ALL; } + + @Override + public Set<UpdatedRef> getUpdatedRefs() { + return Set.of( + new GitBatchRefUpdateListener.UpdatedRef() { + + @Override + public String getRefName() { + return ref; + } + + @Override + public String getOldObjectId() { + return ObjectId.zeroId().getName(); + } + + @Override + public String getNewObjectId() { + return newObjectId; + } + + @Override + public boolean isCreate() { + return type == ReceiveCommand.Type.CREATE; + } + + @Override + public boolean isDelete() { + return type == ReceiveCommand.Type.DELETE; + } + + @Override + public boolean isNonFastForward() { + return type == ReceiveCommand.Type.UPDATE_NONFASTFORWARD; + } + }); + } + + @Override + public Set<String> getRefNames() { + return Set.of(ref); + } }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationFanoutConfigIT.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationFanoutConfigIT.java index ee5876f..ff8265f 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationFanoutConfigIT.java +++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationFanoutConfigIT.java
@@ -27,7 +27,7 @@ import com.google.gerrit.acceptance.testsuite.project.ProjectOperations; import com.google.gerrit.entities.Project; import com.google.gerrit.extensions.api.projects.BranchInput; -import com.google.gerrit.extensions.events.GitReferenceUpdatedListener; +import com.google.gerrit.extensions.events.GitBatchRefUpdateListener; import com.google.gerrit.server.config.SitePaths; import com.google.inject.Inject; import com.googlesource.gerrit.plugins.replication.AutoReloadConfigDecorator; @@ -105,14 +105,14 @@ String sourceRef = pushResult.getPatchSet().refName(); ReplicationQueue pullReplicationQueue = getInstance(ReplicationQueue.class); - GitReferenceUpdatedListener.Event event = + GitBatchRefUpdateListener.Event event = new FakeGitReferenceUpdatedEvent( project, sourceRef, ObjectId.zeroId().getName(), sourceCommit.getId().getName(), ReceiveCommand.Type.CREATE); - pullReplicationQueue.onGitReferenceUpdated(event); + pullReplicationQueue.onGitBatchRefUpdate(event); try (Repository repo = repoManager.openRepository(project)) { waitUntil(() -> checkedGetRef(repo, sourceRef) != null); @@ -141,14 +141,14 @@ RevCommit sourceCommit = pushResult.getCommit(); final String sourceRef = pushResult.getPatchSet().refName(); ReplicationQueue pullReplicationQueue = getInstance(ReplicationQueue.class); - GitReferenceUpdatedListener.Event event = + GitBatchRefUpdateListener.Event event = new FakeGitReferenceUpdatedEvent( project, sourceRef, ObjectId.zeroId().getName(), sourceCommit.getId().getName(), ReceiveCommand.Type.CREATE); - pullReplicationQueue.onGitReferenceUpdated(event); + pullReplicationQueue.onGitBatchRefUpdate(event); try (Repository repo = repoManager.openRepository(project)) { waitUntil(() -> checkedGetRef(repo, sourceRef) != null); @@ -174,14 +174,14 @@ ReplicationQueue pullReplicationQueue = plugin.getSysInjector().getInstance(ReplicationQueue.class); - GitReferenceUpdatedListener.Event event = + GitBatchRefUpdateListener.Event event = new FakeGitReferenceUpdatedEvent( project, newBranch, ObjectId.zeroId().getName(), branchRevision, ReceiveCommand.Type.CREATE); - pullReplicationQueue.onGitReferenceUpdated(event); + pullReplicationQueue.onGitBatchRefUpdate(event); try (Repository repo = repoManager.openRepository(project); Repository sourceRepo = repoManager.openRepository(project)) {
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationIT.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationIT.java index 86b22b2..6fd5cb3 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationIT.java +++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationIT.java
@@ -30,7 +30,7 @@ import com.google.gerrit.entities.RefNames; import com.google.gerrit.extensions.api.changes.NotifyHandling; import com.google.gerrit.extensions.api.projects.BranchInput; -import com.google.gerrit.extensions.events.GitReferenceUpdatedListener; +import com.google.gerrit.extensions.events.GitBatchRefUpdateListener; import com.google.gerrit.extensions.events.HeadUpdatedListener; import com.google.gerrit.extensions.events.ProjectDeletedListener; import com.google.gerrit.extensions.restapi.RestApiException; @@ -91,14 +91,14 @@ String sourceRef = pushResult.getPatchSet().refName(); ReplicationQueue pullReplicationQueue = getInstance(ReplicationQueue.class); - GitReferenceUpdatedListener.Event event = + GitBatchRefUpdateListener.Event event = new FakeGitReferenceUpdatedEvent( project, sourceRef, ObjectId.zeroId().getName(), sourceCommit.getId().getName(), ReceiveCommand.Type.CREATE); - pullReplicationQueue.onGitReferenceUpdated(event); + pullReplicationQueue.onGitBatchRefUpdate(event); try (Repository repo = repoManager.openRepository(project)) { waitUntil(() -> checkedGetRef(repo, sourceRef) != null); @@ -124,14 +124,14 @@ ReplicationQueue pullReplicationQueue = plugin.getSysInjector().getInstance(ReplicationQueue.class); - GitReferenceUpdatedListener.Event event = + GitBatchRefUpdateListener.Event event = new FakeGitReferenceUpdatedEvent( project, newBranch, ObjectId.zeroId().getName(), branchRevision, ReceiveCommand.Type.CREATE); - pullReplicationQueue.onGitReferenceUpdated(event); + pullReplicationQueue.onGitBatchRefUpdate(event); try (Repository repo = repoManager.openRepository(project); Repository sourceRepo = repoManager.openRepository(project)) { @@ -167,14 +167,14 @@ ReplicationQueue pullReplicationQueue = plugin.getSysInjector().getInstance(ReplicationQueue.class); - GitReferenceUpdatedListener.Event event = + GitBatchRefUpdateListener.Event event = new FakeGitReferenceUpdatedEvent( project, newBranch, ObjectId.zeroId().getName(), branchRevision, ReceiveCommand.Type.CREATE); - pullReplicationQueue.onGitReferenceUpdated(event); + pullReplicationQueue.onGitBatchRefUpdate(event); try (Repository repo = repoManager.openRepository(project)) { waitUntil(() -> checkedGetRef(repo, newBranch) != null); @@ -193,14 +193,14 @@ assertThat(pushedRefs).hasSize(1); assertThat(pushedRefs.iterator().next().getStatus()).isEqualTo(Status.OK); - GitReferenceUpdatedListener.Event forcedPushEvent = + GitBatchRefUpdateListener.Event forcedPushEvent = new FakeGitReferenceUpdatedEvent( project, newBranch, branchRevision, amendedCommit.getId().getName(), ReceiveCommand.Type.UPDATE_NONFASTFORWARD); - pullReplicationQueue.onGitReferenceUpdated(forcedPushEvent); + pullReplicationQueue.onGitBatchRefUpdate(forcedPushEvent); try (Repository repo = repoManager.openRepository(project); Repository sourceRepo = repoManager.openRepository(project)) { @@ -232,14 +232,14 @@ String sourceRef = pushResult.getPatchSet().refName(); ReplicationQueue pullReplicationQueue = getInstance(ReplicationQueue.class); - GitReferenceUpdatedListener.Event event = + GitBatchRefUpdateListener.Event event = new FakeGitReferenceUpdatedEvent( project, sourceRef, ObjectId.zeroId().getName(), sourceCommit.getId().getName(), ReceiveCommand.Type.CREATE); - pullReplicationQueue.onGitReferenceUpdated(event); + pullReplicationQueue.onGitBatchRefUpdate(event); try (Repository repo = repoManager.openRepository(project)) { waitUntil(() -> checkedGetRef(repo, sourceRef) != null); @@ -273,14 +273,14 @@ ReplicationQueue pullReplicationQueue = plugin.getSysInjector().getInstance(ReplicationQueue.class); - GitReferenceUpdatedListener.Event event = + GitBatchRefUpdateListener.Event event = new FakeGitReferenceUpdatedEvent( project, newBranch, ObjectId.zeroId().getName(), branchRevision, ReceiveCommand.Type.CREATE); - pullReplicationQueue.onGitReferenceUpdated(event); + pullReplicationQueue.onGitBatchRefUpdate(event); try (Repository repo = repoManager.openRepository(project); Repository sourceRepo = repoManager.openRepository(project)) { @@ -364,14 +364,14 @@ String sourceRef = pushResult.getPatchSet().refName(); ReplicationQueue pullReplicationQueue = getInstance(ReplicationQueue.class); - GitReferenceUpdatedListener.Event event = + GitBatchRefUpdateListener.Event event = new FakeGitReferenceUpdatedEvent( project, sourceRef, ObjectId.zeroId().getName(), sourceCommit.getId().getName(), ReceiveCommand.Type.CREATE); - pullReplicationQueue.onGitReferenceUpdated(event); + pullReplicationQueue.onGitBatchRefUpdate(event); try (Repository repo = repoManager.openRepository(project)) { waitUntil(() -> checkedGetRef(repo, sourceRef) != null);
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationWithGitHttpTransportProtocolIT.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationWithGitHttpTransportProtocolIT.java index d8e5947..2d1f51f 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationWithGitHttpTransportProtocolIT.java +++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/PullReplicationWithGitHttpTransportProtocolIT.java
@@ -21,7 +21,7 @@ import com.google.gerrit.acceptance.TestPlugin; import com.google.gerrit.acceptance.UseLocalDisk; import com.google.gerrit.acceptance.config.GerritConfig; -import com.google.gerrit.extensions.events.GitReferenceUpdatedListener; +import com.google.gerrit.extensions.events.GitBatchRefUpdateListener; import java.io.IOException; import java.util.List; import java.util.Optional; @@ -82,14 +82,14 @@ String sourceRef = pushResult.getPatchSet().refName(); ReplicationQueue pullReplicationQueue = getInstance(ReplicationQueue.class); - GitReferenceUpdatedListener.Event event = + GitBatchRefUpdateListener.Event event = new FakeGitReferenceUpdatedEvent( project, sourceRef, ObjectId.zeroId().getName(), sourceCommit.getId().getName(), ReceiveCommand.Type.CREATE); - pullReplicationQueue.onGitReferenceUpdated(event); + pullReplicationQueue.onGitBatchRefUpdate(event); try (Repository repo = repoManager.openRepository(project)) { waitUntil(() -> checkedGetRef(repo, sourceRef) != null);
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/ReplicationQueueTest.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/ReplicationQueueTest.java index 927aec2..e7de264 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/ReplicationQueueTest.java +++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/ReplicationQueueTest.java
@@ -21,6 +21,7 @@ import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; @@ -33,8 +34,8 @@ import com.google.gerrit.entities.Project; import com.google.gerrit.extensions.api.changes.NotifyHandling; import com.google.gerrit.extensions.common.AccountInfo; -import com.google.gerrit.extensions.events.GitReferenceUpdatedListener; -import com.google.gerrit.extensions.events.GitReferenceUpdatedListener.Event; +import com.google.gerrit.extensions.events.GitBatchRefUpdateListener; +import com.google.gerrit.extensions.events.GitBatchRefUpdateListener.UpdatedRef; import com.google.gerrit.extensions.events.ProjectDeletedListener; import com.google.gerrit.extensions.registration.DynamicItem; import com.google.gerrit.metrics.DisabledMetricMaker; @@ -54,6 +55,8 @@ import java.util.Arrays; import java.util.List; import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; import org.apache.http.client.ClientProtocolException; import org.eclipse.jgit.errors.LargeObjectException; import org.eclipse.jgit.lib.ObjectId; @@ -64,6 +67,7 @@ import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Captor; +import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; @@ -161,57 +165,84 @@ @Test public void shouldCallSendObjectWhenMetaRef() throws ClientProtocolException, IOException { - Event event = new TestEvent("refs/changes/01/1/meta"); + TestEvent event = new TestEvent("refs/changes/01/1/meta"); objectUnderTest.start(); - objectUnderTest.onGitReferenceUpdated(event); + objectUnderTest.onGitBatchRefUpdate(event); verify(fetchRestApiClient).callSendObjects(any(), anyString(), any(), any()); } @Test public void shouldCallInitProjectWhenProjectIsMissing() throws IOException { - Event event = new TestEvent("refs/changes/01/1/meta"); + TestEvent event = new TestEvent("refs/changes/01/1/meta"); when(httpResult.isSuccessful()).thenReturn(false); when(httpResult.isProjectMissing(any())).thenReturn(true); when(source.isCreateMissingRepositories()).thenReturn(true); objectUnderTest.start(); - objectUnderTest.onGitReferenceUpdated(event); + objectUnderTest.onGitBatchRefUpdate(event); verify(fetchRestApiClient).initProject(any(), any()); } @Test public void shouldNotCallInitProjectWhenReplicateNewRepositoriesNotSet() throws IOException { - Event event = new TestEvent("refs/changes/01/1/meta"); + TestEvent event = new TestEvent("refs/changes/01/1/meta"); when(httpResult.isSuccessful()).thenReturn(false); when(httpResult.isProjectMissing(any())).thenReturn(true); when(source.isCreateMissingRepositories()).thenReturn(false); objectUnderTest.start(); - objectUnderTest.onGitReferenceUpdated(event); + objectUnderTest.onGitBatchRefUpdate(event); verify(fetchRestApiClient, never()).initProject(any(), any()); } @Test public void shouldCallSendObjectWhenPatchSetRef() throws ClientProtocolException, IOException { - Event event = new TestEvent("refs/changes/01/1/1"); + TestEvent event = new TestEvent("refs/changes/01/1/1"); objectUnderTest.start(); - objectUnderTest.onGitReferenceUpdated(event); + objectUnderTest.onGitBatchRefUpdate(event); verify(fetchRestApiClient).callSendObjects(any(), anyString(), any(), any()); } @Test + public void shouldCallSendObjectReorderingRefsHavingMetaAtTheEnd() + throws ClientProtocolException, IOException { + sendRefUpdatedEvents("refs/changes/01/1/meta", "refs/changes/01/1/1"); + verifySendObjectOrdering("refs/changes/01/1/1", "refs/changes/01/1/meta"); + } + + @Test + public void shouldCallSendObjectKeepingMetaAtTheEnd() + throws ClientProtocolException, IOException { + sendRefUpdatedEvents("refs/changes/01/1/1", "refs/changes/01/1/meta"); + verifySendObjectOrdering("refs/changes/01/1/1", "refs/changes/01/1/meta"); + } + + private void sendRefUpdatedEvents(String firstRef, String secondRef) { + objectUnderTest.start(); + objectUnderTest.onGitBatchRefUpdate(new TestEvent(firstRef, secondRef)); + } + + private void verifySendObjectOrdering(String firstRef, String secondRef) + throws ClientProtocolException, IOException { + InOrder inOrder = inOrder(fetchRestApiClient); + + inOrder.verify(fetchRestApiClient).callSendObjects(any(), eq(firstRef), any(), any()); + inOrder.verify(fetchRestApiClient).callSendObjects(any(), eq(secondRef), any(), any()); + } + + @Test public void shouldFallbackToCallFetchWhenIOException() throws ClientProtocolException, IOException, LargeObjectException { - Event event = new TestEvent("refs/changes/01/1/meta"); + TestEvent event = new TestEvent("refs/changes/01/1/meta"); objectUnderTest.start(); when(revReader.read(any(), any(), anyString(), anyInt())).thenThrow(IOException.class); - objectUnderTest.onGitReferenceUpdated(event); + objectUnderTest.onGitBatchRefUpdate(event); verify(fetchRestApiClient).callFetch(any(), anyString(), any()); } @@ -219,12 +250,12 @@ @Test public void shouldFallbackToCallFetchWhenLargeRef() throws ClientProtocolException, IOException, LargeObjectException { - Event event = new TestEvent("refs/changes/01/1/1"); + TestEvent event = new TestEvent("refs/changes/01/1/1"); objectUnderTest.start(); when(revReader.read(any(), any(), anyString(), anyInt())).thenReturn(Optional.empty()); - objectUnderTest.onGitReferenceUpdated(event); + objectUnderTest.onGitBatchRefUpdate(event); verify(fetchRestApiClient).callFetch(any(), anyString(), any()); } @@ -232,7 +263,7 @@ @Test public void shouldFallbackToCallFetchWhenParentObjectIsMissing() throws ClientProtocolException, IOException { - Event event = new TestEvent("refs/changes/01/1/1"); + TestEvent event = new TestEvent("refs/changes/01/1/1"); objectUnderTest.start(); when(httpResult.isSuccessful()).thenReturn(false); @@ -240,7 +271,7 @@ when(fetchRestApiClient.callSendObjects(any(), anyString(), any(), any())) .thenReturn(httpResult); - objectUnderTest.onGitReferenceUpdated(event); + objectUnderTest.onGitBatchRefUpdate(event); verify(fetchRestApiClient).callFetch(any(), anyString(), any()); } @@ -248,7 +279,7 @@ @Test public void shouldFallbackToApplyAllParentObjectsWhenParentObjectIsMissingOnMetaRef() throws ClientProtocolException, IOException { - Event event = new TestEvent("refs/changes/01/1/meta"); + TestEvent event = new TestEvent("refs/changes/01/1/meta"); objectUnderTest.start(); when(httpResult.isSuccessful()).thenReturn(false, true); @@ -256,7 +287,7 @@ when(fetchRestApiClient.callSendObjects(any(), anyString(), any(), any())) .thenReturn(httpResult); - objectUnderTest.onGitReferenceUpdated(event); + objectUnderTest.onGitBatchRefUpdate(event); verify(fetchRestApiClient, times(2)) .callSendObjects(any(), anyString(), revisionsDataCaptor.capture(), any()); @@ -291,16 +322,16 @@ () -> revReader, applyObjectMetrics, fetchMetrics); - Event event = new TestEvent("refs/multi-site/version"); - objectUnderTest.onGitReferenceUpdated(event); + TestEvent event = new TestEvent("refs/multi-site/version"); + objectUnderTest.onGitBatchRefUpdate(event); verifyZeroInteractions(wq, rd, dis, sl, fetchClientFactory, accountInfo); } @Test public void shouldSkipEventWhenStarredChangesRef() { - Event event = new TestEvent("refs/starred-changes/41/2941/1000000"); - objectUnderTest.onGitReferenceUpdated(event); + TestEvent event = new TestEvent("refs/starred-changes/41/2941/1000000"); + objectUnderTest.onGitBatchRefUpdate(event); verifyZeroInteractions(wq, rd, dis, sl, fetchClientFactory, accountInfo); } @@ -365,24 +396,22 @@ return createTempDirectory(prefix); } - private class TestEvent implements GitReferenceUpdatedListener.Event { + private static class TestEvent implements GitBatchRefUpdateListener.Event { private String refName; private String projectName; - private ObjectId newObjectId; + private List<UpdatedRef> refs; - public TestEvent(String refName) { - this(refName, "defaultProject", ObjectId.zeroId()); + public TestEvent(String... refNames) { + this( + "defaultProject", + Arrays.stream(refNames) + .map(refName -> updateRef(refName, ObjectId.zeroId())) + .collect(Collectors.toUnmodifiableList())); } - public TestEvent(String refName, String projectName, ObjectId newObjectId) { - this.refName = refName; + public TestEvent(String projectName, List<UpdatedRef> refs) { this.projectName = projectName; - this.newObjectId = newObjectId; - } - - @Override - public String getRefName() { - return refName; + this.refs = refs; } @Override @@ -396,34 +425,55 @@ } @Override - public String getOldObjectId() { - return ObjectId.zeroId().getName(); - } - - @Override - public String getNewObjectId() { - return newObjectId.getName(); - } - - @Override - public boolean isCreate() { - return false; - } - - @Override - public boolean isDelete() { - return false; - } - - @Override - public boolean isNonFastForward() { - return false; - } - - @Override public AccountInfo getUpdater() { return null; } + + @Override + public Set<UpdatedRef> getUpdatedRefs() { + return refs.stream().collect(Collectors.toSet()); + } + + private static final GitBatchRefUpdateListener.UpdatedRef updateRef( + String refName, ObjectId refObjectId) { + return new GitBatchRefUpdateListener.UpdatedRef() { + + @Override + public String getRefName() { + return refName; + } + + @Override + public String getOldObjectId() { + return ObjectId.zeroId().getName(); + } + + @Override + public String getNewObjectId() { + return refObjectId.getName(); + } + + @Override + public boolean isCreate() { + return false; + } + + @Override + public boolean isDelete() { + return false; + } + + @Override + public boolean isNonFastForward() { + return false; + } + }; + } + + @Override + public Set<String> getRefNames() { + return Set.of(refName); + } } private class FakeProjectDeletedEvent implements ProjectDeletedListener.Event {