Propagate FetchRefReplicatedEvent upon a Ref fetch

Bug: Issue 13893
Change-Id: I9e7b03b11a11fcd9c19d80dede17100a8c1f7534
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/FetchResultProcessing.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/FetchResultProcessing.java
index cffc1f6..2d51239 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/FetchResultProcessing.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/FetchResultProcessing.java
@@ -18,6 +18,7 @@
 import com.google.gerrit.server.events.EventDispatcher;
 import com.google.gerrit.server.events.RefEvent;
 import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.inject.Inject;
 import java.lang.ref.WeakReference;
 import java.util.concurrent.atomic.AtomicBoolean;
 import org.eclipse.jgit.lib.RefUpdate;
@@ -69,11 +70,15 @@
   }
 
   public static class CommandProcessing extends FetchResultProcessing {
+    private static final FluentLogger logger = FluentLogger.forEnclosingClass();
     private WeakReference<Command> sshCommand;
     private AtomicBoolean hasError = new AtomicBoolean();
+    private final EventDispatcher dispatcher;
 
-    public CommandProcessing(Command sshCommand) {
+    @Inject
+    public CommandProcessing(Command sshCommand, EventDispatcher dispatcher) {
       this.sshCommand = new WeakReference<>(sshCommand);
+      this.dispatcher = dispatcher;
     }
 
     @Override
@@ -112,6 +117,14 @@
         sb.append(")");
       }
       writeStdOut(sb.toString());
+      try {
+        dispatcher.postEvent(
+            new FetchRefReplicatedEvent(
+                project, ref, resolveNodeName(uri), status, refUpdateResult));
+      } catch (PermissionBackendException e) {
+        logger.atSevere().withCause(e).log(
+            "Cannot post event for ref '%s', project %s", ref, project);
+      }
     }
 
     @Override
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/StartFetchCommand.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/StartFetchCommand.java
index a3497e6..6ababe9 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/StartFetchCommand.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/StartFetchCommand.java
@@ -15,6 +15,8 @@
 package com.googlesource.gerrit.plugins.replication.pull;
 
 import com.google.gerrit.extensions.annotations.RequiresCapability;
+import com.google.gerrit.extensions.registration.DynamicItem;
+import com.google.gerrit.server.events.EventDispatcher;
 import com.google.gerrit.sshd.CommandMetaData;
 import com.google.gerrit.sshd.SshCommand;
 import com.google.inject.Inject;
@@ -54,6 +56,8 @@
 
   @Inject private ReplicationState.Factory fetchReplicationStateFactory;
 
+  @Inject private DynamicItem<EventDispatcher> eventDispatcher;
+
   @Override
   protected void run() throws Failure {
     if (all && projectPatterns.size() > 0) {
@@ -61,7 +65,8 @@
     }
 
     ReplicationState state =
-        fetchReplicationStateFactory.create(new FetchResultProcessing.CommandProcessing(this));
+        fetchReplicationStateFactory.create(
+            new FetchResultProcessing.CommandProcessing(this, eventDispatcher.get()));
     Future<?> future = null;
 
     ReplicationFilter projectFilter;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/FetchCommand.java b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/FetchCommand.java
index 7470c2c..1088d9b 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/FetchCommand.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/pull/api/FetchCommand.java
@@ -15,6 +15,8 @@
 package com.googlesource.gerrit.plugins.replication.pull.api;
 
 import com.google.gerrit.entities.Project;
+import com.google.gerrit.extensions.registration.DynamicItem;
+import com.google.gerrit.server.events.EventDispatcher;
 import com.google.inject.Inject;
 import com.googlesource.gerrit.plugins.replication.pull.Command;
 import com.googlesource.gerrit.plugins.replication.pull.FetchResultProcessing;
@@ -34,22 +36,26 @@
   private ReplicationState.Factory fetchReplicationStateFactory;
   private PullReplicationStateLogger fetchStateLog;
   private SourcesCollection sources;
+  private final DynamicItem<EventDispatcher> eventDispatcher;
 
   @Inject
   public FetchCommand(
       ReplicationState.Factory fetchReplicationStateFactory,
       PullReplicationStateLogger fetchStateLog,
-      SourcesCollection sources) {
+      SourcesCollection sources,
+      DynamicItem<EventDispatcher> eventDispatcher) {
     this.fetchReplicationStateFactory = fetchReplicationStateFactory;
     this.fetchStateLog = fetchStateLog;
     this.sources = sources;
+    this.eventDispatcher = eventDispatcher;
   }
 
   public void fetch(Project.NameKey name, String label, String refName)
       throws InterruptedException, ExecutionException, RemoteConfigurationMissingException,
           TimeoutException {
     ReplicationState state =
-        fetchReplicationStateFactory.create(new FetchResultProcessing.CommandProcessing(this));
+        fetchReplicationStateFactory.create(
+            new FetchResultProcessing.CommandProcessing(this, eventDispatcher.get()));
     Optional<Source> source =
         sources.getAll().stream().filter(s -> s.getRemoteConfigName().equals(label)).findFirst();
     if (!source.isPresent()) {
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 f0f1c54..77dc947 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
@@ -21,6 +21,7 @@
 
 import com.google.gerrit.server.events.EventDispatcher;
 import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.googlesource.gerrit.plugins.replication.pull.FetchResultProcessing.CommandProcessing;
 import com.googlesource.gerrit.plugins.replication.pull.FetchResultProcessing.GitUpdateProcessing;
 import com.googlesource.gerrit.plugins.replication.pull.ReplicationState.RefFetchResult;
 import java.net.URISyntaxException;
@@ -32,15 +33,20 @@
 public class FetchGitUpdateProcessingTest {
   private EventDispatcher dispatcherMock;
   private GitUpdateProcessing gitUpdateProcessing;
+  private CommandProcessing commandProcessing;
+  private Command sshCommandMock;
 
   @Before
   public void setUp() throws Exception {
     dispatcherMock = mock(EventDispatcher.class);
     gitUpdateProcessing = new GitUpdateProcessing(dispatcherMock);
+    sshCommandMock = mock(Command.class);
+    commandProcessing = new CommandProcessing(sshCommandMock, dispatcherMock);
   }
 
   @Test
-  public void headRefReplicated() throws URISyntaxException, PermissionBackendException {
+  public void headRefReplicatedInGitUpdateProcessing()
+      throws URISyntaxException, PermissionBackendException {
     FetchRefReplicatedEvent expectedEvent =
         new FetchRefReplicatedEvent(
             "someProject",
@@ -59,6 +65,26 @@
   }
 
   @Test
+  public void headRefReplicatedInCommandProcessing()
+      throws URISyntaxException, PermissionBackendException {
+    FetchRefReplicatedEvent expectedEvent =
+        new FetchRefReplicatedEvent(
+            "someProject",
+            "refs/heads/master",
+            "someHost",
+            RefFetchResult.SUCCEEDED,
+            RefUpdate.Result.NEW);
+
+    commandProcessing.onOneProjectReplicationDone(
+        "someProject",
+        "refs/heads/master",
+        new URIish("git://someHost/someProject.git"),
+        RefFetchResult.SUCCEEDED,
+        RefUpdate.Result.NEW);
+    verify(dispatcherMock, times(1)).postEvent(eq(expectedEvent));
+  }
+
+  @Test
   public void changeRefReplicated() throws URISyntaxException, PermissionBackendException {
     FetchRefReplicatedEvent expectedEvent =
         new FetchRefReplicatedEvent(
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/FetchCommandTest.java b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/FetchCommandTest.java
index e625e0f..4cdad48 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/FetchCommandTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/replication/pull/api/FetchCommandTest.java
@@ -25,6 +25,8 @@
 
 import com.google.common.collect.Lists;
 import com.google.gerrit.entities.Project;
+import com.google.gerrit.extensions.registration.DynamicItem;
+import com.google.gerrit.server.events.EventDispatcher;
 import com.googlesource.gerrit.plugins.replication.pull.PullReplicationStateLogger;
 import com.googlesource.gerrit.plugins.replication.pull.ReplicationState;
 import com.googlesource.gerrit.plugins.replication.pull.Source;
@@ -51,6 +53,7 @@
   @Mock PullReplicationStateLogger fetchStateLog;
   @Mock Source source;
   @Mock SourcesCollection sources;
+  @Mock DynamicItem<EventDispatcher> eventDispatcher;
 
   @SuppressWarnings("rawtypes")
   @Mock
@@ -73,7 +76,8 @@
     when(sources.getAll()).thenReturn(Lists.newArrayList(source));
     when(source.schedule(projectName, REF_NAME_TO_FETCH, state, true))
         .thenReturn(CompletableFuture.completedFuture(null));
-    objectUnderTest = new FetchCommand(fetchReplicationStateFactory, fetchStateLog, sources);
+    objectUnderTest =
+        new FetchCommand(fetchReplicationStateFactory, fetchStateLog, sources, eventDispatcher);
   }
 
   @Test