Merge branch 'stable-3.5' into stable-3.6
* stable-3.5:
Increase FetchOne coverage with unit tests
Display the in-flight taskId when a runway conflict is detected
Restore the fetching of all refs with empty delta
Allow to filter out refs from the fetch-replication deltas
Do not accumulate replication events with retrying tasks
Add replication taskId during the execution of the fetch
Allow FetchOne to retry the failed ref only
Change-Id: Idf86be68b3678019a85e300e7174786bbd176b15
diff --git a/example-setup/broker/Dockerfile b/example-setup/broker/Dockerfile
index 1b3038c..566e839 100644
--- a/example-setup/broker/Dockerfile
+++ b/example-setup/broker/Dockerfile
@@ -1,4 +1,4 @@
-FROM gerritcodereview/gerrit:3.5.5-almalinux8
+FROM gerritcodereview/gerrit:3.6.3-almalinux8
USER root
diff --git a/example-setup/http/Dockerfile b/example-setup/http/Dockerfile
index 552a114..b966b5f 100644
--- a/example-setup/http/Dockerfile
+++ b/example-setup/http/Dockerfile
@@ -1,4 +1,4 @@
-FROM gerritcodereview/gerrit:3.5.5-almalinux8
+FROM gerritcodereview/gerrit:3.6.3-almalinux8
USER root
diff --git a/external_plugin_deps.bzl b/external_plugin_deps.bzl
index 5d2ba13..3bf728d 100644
--- a/external_plugin_deps.bzl
+++ b/external_plugin_deps.bzl
@@ -3,6 +3,6 @@
def external_plugin_deps():
maven_jar(
name = "events-broker",
- artifact = "com.gerritforge:events-broker:3.5.0.1",
- sha1 = "af192a8bceaf7ff54d19356f9bfe1f1e83634b40",
+ artifact = "com.gerritforge:events-broker:3.6.0-rc3",
+ sha1 = "cb398afa4f76367be5c62b99a7ffce74ae1d3d8b",
)
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 380ac8e..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,21 +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(
- event.getProjectName(),
- ObjectId.fromString(event.getNewObjectId()),
- event.getRefName(),
- event.isDelete());
- }
+ 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
@@ -174,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";
@@ -189,34 +198,39 @@
return !refsFilter.match(refName);
}
- private void fire(String projectName, ObjectId objectId, String refName, boolean isDelete) {
+ private void fire(ReferenceUpdatedEvent event) {
ReplicationState state = new ReplicationState(new GitUpdateProcessing(dispatcher.get()));
- fire(Project.nameKey(projectName), objectId, refName, isDelete, state);
+ fire(event, state);
state.markAllFetchTasksScheduled();
}
- private void fire(
- Project.NameKey project,
- ObjectId objectId,
- String refName,
- boolean isDelete,
- ReplicationState state) {
+ private void fire(ReferenceUpdatedEvent event, ReplicationState state) {
if (!running) {
stateLog.warn(
"Replication plugin did not finish startup before event, event replication is postponed",
state);
- beforeStartupEventsQueue.add(
- ReferenceUpdatedEvent.create(project.get(), refName, objectId, isDelete));
+ beforeStartupEventsQueue.add(event);
return;
}
ForkJoinPool fetchCallsPool = null;
try {
- fetchCallsPool = new ForkJoinPool(sources.get().getAll().size());
+ List<Source> allSources = sources.get().getAll();
+ int numSources = allSources.size();
+ if (numSources == 0) {
+ repLog.debug("No replication sources configured -> skipping fetch");
+ return;
+ }
+ fetchCallsPool = new ForkJoinPool(numSources);
final Consumer<Source> callFunction =
- callFunction(project, objectId, refName, isDelete, state);
+ callFunction(
+ Project.nameKey(event.projectName()),
+ event.objectId(),
+ event.refName(),
+ event.isDelete(),
+ state);
fetchCallsPool
- .submit(() -> sources.get().getAll().parallelStream().forEach(callFunction))
+ .submit(() -> allSources.parallelStream().forEach(callFunction))
.get(fetchCallsTimeout, TimeUnit.MILLISECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
stateLog.error(
@@ -491,7 +505,7 @@
String eventKey = String.format("%s:%s", event.projectName(), event.refName());
if (!eventsReplayed.contains(eventKey)) {
repLog.info("Firing pending task {}", event);
- fire(event.projectName(), event.objectId(), event.refName(), event.isDelete());
+ fire(event);
eventsReplayed.add(eventKey);
}
}
@@ -517,6 +531,14 @@
projectName, refName, objectId, isDelete);
}
+ static ReferenceUpdatedEvent from(String projectName, UpdatedRef updateRef) {
+ return ReferenceUpdatedEvent.create(
+ projectName,
+ updateRef.getRefName(),
+ ObjectId.fromString(updateRef.getNewObjectId()),
+ updateRef.isDelete());
+ }
+
public abstract String projectName();
public abstract String refName();
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/DeleteRefCommand.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/DeleteRefCommand.java
index f897012..e49c8b6 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/DeleteRefCommand.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/DeleteRefCommand.java
@@ -35,7 +35,6 @@
import com.googlesource.gerrit.plugins.replication.pull.ReplicationState;
import com.googlesource.gerrit.plugins.replication.pull.Source;
import com.googlesource.gerrit.plugins.replication.pull.SourcesCollection;
-import com.googlesource.gerrit.plugins.replication.pull.fetch.ApplyObject;
import com.googlesource.gerrit.plugins.replication.pull.fetch.RefUpdateState;
import java.io.IOException;
import java.util.Optional;
@@ -49,7 +48,6 @@
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private final PullReplicationStateLogger fetchStateLog;
- private final ApplyObject applyObject;
private final DynamicItem<EventDispatcher> eventDispatcher;
private final ProjectCache projectCache;
private final SourcesCollection sourcesCollection;
@@ -61,13 +59,11 @@
PullReplicationStateLogger fetchStateLog,
ProjectCache projectCache,
SourcesCollection sourcesCollection,
- ApplyObject applyObject,
PermissionBackend permissionBackend,
DynamicItem<EventDispatcher> eventDispatcher,
LocalGitRepositoryManagerProvider gitManagerProvider) {
this.fetchStateLog = fetchStateLog;
this.projectCache = projectCache;
- this.applyObject = applyObject;
this.eventDispatcher = eventDispatcher;
this.sourcesCollection = sourcesCollection;
this.permissionBackend = permissionBackend;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/fetch/CGitFetchValidator.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/fetch/CGitFetchValidator.java
index 9a10898..434c0f0 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/fetch/CGitFetchValidator.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/fetch/CGitFetchValidator.java
@@ -35,7 +35,7 @@
@Override
public Void visit(AssistedInjectBinding<? extends FetchFactory> binding) {
- TypeLiteral<CGitFetch> nativeGitFetchType = new TypeLiteral<CGitFetch>() {};
+ TypeLiteral<CGitFetch> nativeGitFetchType = new TypeLiteral<>() {};
for (AssistedMethod method : binding.getAssistedMethods()) {
if (method.getImplementationType().equals(nativeGitFetchType)) {
String[] command = new String[] {"git", "--version"};
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/fetch/PermanentTransportException.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/fetch/PermanentTransportException.java
index acb68cf..0fa89b5 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/fetch/PermanentTransportException.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/fetch/PermanentTransportException.java
@@ -14,7 +14,7 @@
package com.googlesource.gerrit.plugins.replication.pull.fetch;
-import com.jcraft.jsch.JSchException;
+import org.apache.sshd.common.SshException;
import org.eclipse.jgit.errors.TransportException;
public class PermanentTransportException extends TransportException {
@@ -26,7 +26,8 @@
public static TransportException wrapIfPermanentTransportException(TransportException e) {
Throwable cause = e.getCause();
- if (cause instanceof JSchException && cause.getMessage().startsWith("UnknownHostKey:")) {
+ if (cause instanceof SshException
+ && cause.getMessage().startsWith("Failed (UnsupportedCredentialItem) to execute:")) {
return new PermanentTransportException("Terminal fetch failure", e);
}
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/FetchGitUpdateProcessingTest.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/FetchGitUpdateProcessingTest.java
index 68044b4..5a26054 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/FetchGitUpdateProcessingTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/FetchGitUpdateProcessingTest.java
@@ -47,8 +47,7 @@
}
@Test
- public void headRefReplicatedInGitUpdateProcessing()
- throws URISyntaxException, PermissionBackendException {
+ public void headRefReplicatedInGitUpdateProcessing() throws PermissionBackendException {
FetchRefReplicatedEvent expectedEvent =
new FetchRefReplicatedEvent(
"someProject",
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/PermanentFailureExceptionTest.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/PermanentFailureExceptionTest.java
index 09a465c..fcb0702 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/PermanentFailureExceptionTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/PermanentFailureExceptionTest.java
@@ -18,7 +18,7 @@
import com.googlesource.gerrit.plugins.replication.pull.fetch.InexistentRefTransportException;
import com.googlesource.gerrit.plugins.replication.pull.fetch.PermanentTransportException;
-import com.jcraft.jsch.JSchException;
+import org.apache.sshd.common.SshException;
import org.eclipse.jgit.errors.TransportException;
import org.junit.Test;
@@ -29,7 +29,9 @@
assertThat(
PermanentTransportException.wrapIfPermanentTransportException(
new TransportException(
- "SSH error", new JSchException("UnknownHostKey: some.place"))))
+ "SSH error",
+ new SshException(
+ "Failed (UnsupportedCredentialItem) to execute: some.commands"))))
.isInstanceOf(PermanentTransportException.class);
}
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 f3c62c5..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)) {
@@ -336,7 +336,6 @@
BranchInput input = new BranchInput();
input.revision = master;
gApi.projects().name(testProjectName).branch(newBranch).create(input);
- String branchRevision = gApi.projects().name(testProjectName).branch(newBranch).get().revision;
ReplicationQueue pullReplicationQueue =
plugin.getSysInjector().getInstance(ReplicationQueue.class);
@@ -365,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 0743cb9..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;
@@ -45,7 +46,6 @@
import com.googlesource.gerrit.plugins.replication.ReplicationConfig;
import com.googlesource.gerrit.plugins.replication.ReplicationFileBasedConfig;
import com.googlesource.gerrit.plugins.replication.pull.api.data.RevisionData;
-import com.googlesource.gerrit.plugins.replication.pull.api.exception.RefUpdateException;
import com.googlesource.gerrit.plugins.replication.pull.client.FetchApiClient;
import com.googlesource.gerrit.plugins.replication.pull.client.FetchRestApiClient;
import com.googlesource.gerrit.plugins.replication.pull.client.HttpResult;
@@ -55,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;
@@ -65,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;
@@ -162,70 +165,97 @@
@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, RefUpdateException {
- Event event = new TestEvent("refs/changes/01/1/meta");
+ throws ClientProtocolException, IOException, LargeObjectException {
+ 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());
}
@Test
public void shouldFallbackToCallFetchWhenLargeRef()
- throws ClientProtocolException, IOException, LargeObjectException, RefUpdateException {
- Event event = new TestEvent("refs/changes/01/1/1");
+ throws ClientProtocolException, IOException, LargeObjectException {
+ 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());
}
@@ -233,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);
@@ -241,7 +271,7 @@
when(fetchRestApiClient.callSendObjects(any(), anyString(), any(), any()))
.thenReturn(httpResult);
- objectUnderTest.onGitReferenceUpdated(event);
+ objectUnderTest.onGitBatchRefUpdate(event);
verify(fetchRestApiClient).callFetch(any(), anyString(), any());
}
@@ -249,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);
@@ -257,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());
@@ -292,22 +322,22 @@
() -> 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);
}
@Test
- public void shouldCallDeleteWhenReplicateProjectDeletionsTrue() throws IOException {
+ public void shouldCallDeleteWhenReplicateProjectDeletionsTrue() {
when(source.wouldDeleteProject(any())).thenReturn(true);
String projectName = "testProject";
@@ -323,7 +353,7 @@
}
@Test
- public void shouldNotCallDeleteWhenProjectNotToDelete() throws IOException {
+ public void shouldNotCallDeleteWhenProjectNotToDelete() {
when(source.wouldDeleteProject(any())).thenReturn(false);
FakeProjectDeletedEvent event = new FakeProjectDeletedEvent("testProject");
@@ -335,7 +365,7 @@
}
@Test
- public void shouldScheduleUpdateHeadWhenWouldFetchProject() throws IOException {
+ public void shouldScheduleUpdateHeadWhenWouldFetchProject() {
when(source.wouldFetchProject(any())).thenReturn(true);
String projectName = "aProject";
@@ -351,7 +381,7 @@
}
@Test
- public void shouldNotScheduleUpdateHeadWhenNotWouldFetchProject() throws IOException {
+ public void shouldNotScheduleUpdateHeadWhenNotWouldFetchProject() {
when(source.wouldFetchProject(any())).thenReturn(false);
String projectName = "aProject";
@@ -366,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
@@ -397,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 {
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/ActionITBase.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/ActionITBase.java
index 20c1fea..e638653 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/ActionITBase.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/ActionITBase.java
@@ -163,7 +163,7 @@
}
public ResponseHandler<Object> assertHttpResponseCode(int responseCode) {
- return new ResponseHandler<Object>() {
+ return new ResponseHandler<>() {
@Override
public Object handleResponse(HttpResponse response)
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/ApplyObjectCommandTest.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/ApplyObjectCommandTest.java
index 9b5ef46..4c188df 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/ApplyObjectCommandTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/ApplyObjectCommandTest.java
@@ -64,7 +64,6 @@
private String sampleCommitObjectId = "9f8d52853089a3cf00c02ff7bd0817bd4353a95a";
private String sampleTreeObjectId = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
- private String sampleBlobObjectId = "b5d7bcf1d1c5b0f0726d10a16c8315f06f900bfb";
@Mock private PullReplicationStateLogger fetchStateLog;
@Mock private ApplyObject applyObject;
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/DeleteRefCommandTest.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/DeleteRefCommandTest.java
index f1f9e44..fc1b02c 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/DeleteRefCommandTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/DeleteRefCommandTest.java
@@ -102,7 +102,6 @@
fetchStateLog,
projectCache,
sourceCollection,
- applyObject,
permissionBackend,
eventDispatcherDataItem,
new LocalGitRepositoryManagerProvider(gitManager));