Merge branch 'stable-3.3'

* stable-3.3:
  Consume scheduled replication events
  Add gerrit CI validation

Change-Id: I48d482a037aaa926db2a62c1ca14082de9dbd907
diff --git a/Jenkinsfile b/Jenkinsfile
new file mode 100644
index 0000000..29d7a35
--- /dev/null
+++ b/Jenkinsfile
@@ -0,0 +1,2 @@
+pluginPipeline(formatCheckId: 'gerritforge:plugins-replication-status-code-style',
+                buildCheckId: 'gerritforge:plugins-replication-status-build-test')
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replicationstatus/EventHandler.java b/src/main/java/com/googlesource/gerrit/plugins/replicationstatus/EventHandler.java
index b197d7f..a2e708f 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replicationstatus/EventHandler.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replicationstatus/EventHandler.java
@@ -15,16 +15,18 @@
 package com.googlesource.gerrit.plugins.replicationstatus;
 
 import static com.googlesource.gerrit.plugins.replicationstatus.ReplicationStatus.ReplicationStatusResult;
+import static com.googlesource.gerrit.plugins.replicationstatus.ReplicationStatus.ReplicationStatusResult.SCHEDULED;
 
 import com.google.common.cache.Cache;
 import com.google.gerrit.common.Nullable;
-import com.google.gerrit.entities.Project;
 import com.google.gerrit.server.config.GerritInstanceId;
 import com.google.gerrit.server.events.Event;
 import com.google.gerrit.server.events.EventListener;
+import com.google.gerrit.server.events.RefEvent;
 import com.google.inject.Inject;
 import com.google.inject.name.Named;
 import com.googlesource.gerrit.plugins.replication.events.RefReplicatedEvent;
+import com.googlesource.gerrit.plugins.replication.events.ReplicationScheduledEvent;
 
 class EventHandler implements EventListener {
   private final Cache<ReplicationStatus.Key, ReplicationStatus> replicationStatusCache;
@@ -44,21 +46,27 @@
     if (shouldConsume(event)) {
       if (event instanceof RefReplicatedEvent) {
         RefReplicatedEvent replEvent = (RefReplicatedEvent) event;
-
-        ReplicationStatus.Key cacheKey =
-            ReplicationStatus.Key.create(
-                Project.nameKey(replEvent.project), replEvent.targetUri, replEvent.ref);
-
-        replicationStatusCache.put(
-            cacheKey,
-            ReplicationStatus.create(
-                ReplicationStatusResult.fromString(replEvent.status), replEvent.eventCreatedOn));
+        putCacheEntry(replEvent, replEvent.targetUri, replEvent.status);
+      } else if (event instanceof ReplicationScheduledEvent) {
+        ReplicationScheduledEvent replEvent = (ReplicationScheduledEvent) event;
+        putCacheEntry(replEvent, replEvent.targetUri, SCHEDULED.name());
       }
     }
   }
 
+  private <T extends RefEvent> void putCacheEntry(T refEvent, String targetNode, String status) {
+    ReplicationStatus.Key cacheKey =
+        ReplicationStatus.Key.create(
+            refEvent.getProjectNameKey(), targetNode, refEvent.getRefName());
+
+    replicationStatusCache.put(
+        cacheKey,
+        ReplicationStatus.create(
+            ReplicationStatusResult.fromString(status), refEvent.eventCreatedOn));
+  }
+
   private boolean shouldConsume(Event event) {
-    return nodeInstanceId == null && event.instanceId == null
-        || nodeInstanceId != null && nodeInstanceId.equals(event.instanceId);
+    return (nodeInstanceId == null && event.instanceId == null)
+        || (nodeInstanceId != null && nodeInstanceId.equals(event.instanceId));
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replicationstatus/ReplicationStatus.java b/src/main/java/com/googlesource/gerrit/plugins/replicationstatus/ReplicationStatus.java
index 438edc2..9287773 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replicationstatus/ReplicationStatus.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replicationstatus/ReplicationStatus.java
@@ -99,6 +99,7 @@
     FAILED,
     NOT_ATTEMPTED,
     SUCCEEDED,
+    SCHEDULED,
     UNKNOWN;
 
     static ReplicationStatusResult fromString(String result) {
@@ -107,6 +108,8 @@
           return SUCCEEDED;
         case "not_attempted":
           return NOT_ATTEMPTED;
+        case "scheduled":
+          return SCHEDULED;
         case "failed":
           return FAILED;
         default:
diff --git a/src/test/java/com/googlesource/gerrit/plugins/replicationstatus/ReplicationStatusIT.java b/src/test/java/com/googlesource/gerrit/plugins/replicationstatus/ReplicationStatusIT.java
index 68508f3..2dc81f1 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/replicationstatus/ReplicationStatusIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/replicationstatus/ReplicationStatusIT.java
@@ -38,6 +38,7 @@
 import com.google.gson.Gson;
 import com.google.inject.Inject;
 import com.googlesource.gerrit.plugins.replication.events.RefReplicatedEvent;
+import com.googlesource.gerrit.plugins.replication.events.ReplicationScheduledEvent;
 import java.io.IOException;
 import java.net.URISyntaxException;
 import java.util.Collections;
@@ -129,6 +130,18 @@
   }
 
   @Test
+  public void shouldReturnScheduledProjectReplicationStatus() throws Exception {
+    long eventCreatedOn = System.currentTimeMillis();
+
+    eventHandler.onEvent(scheduledEvent(null, eventCreatedOn, REF_MASTER, REMOTE));
+    RestResponse result = adminRestSession.get(endpoint(project, REMOTE));
+
+    result.assertOK();
+    assertThat(contentWithoutMagicJson(result))
+        .isEqualTo(scheduledReplicationStatus(REMOTE, project, eventCreatedOn));
+  }
+
+  @Test
   public void shouldConsumeEventsThatHaveNoInstanceId() throws Exception {
     long eventCreatedOn = System.currentTimeMillis();
 
@@ -214,6 +227,16 @@
     return replicatedEvent;
   }
 
+  private ReplicationScheduledEvent scheduledEvent(
+      @Nullable String instanceId, long when, String ref, String remote) throws URISyntaxException {
+    ReplicationScheduledEvent scheduledEvent =
+        new ReplicationScheduledEvent(project.get(), ref, new URIish(remote));
+    scheduledEvent.instanceId = instanceId;
+    scheduledEvent.eventCreatedOn = when;
+
+    return scheduledEvent;
+  }
+
   private RefReplicatedEvent successReplicatedEvent(
       @Nullable String instanceId, long when, String remoteUrl) throws URISyntaxException {
 
@@ -254,12 +277,28 @@
 
   private String successReplicationStatus(String remote, Project.NameKey project, long when)
       throws URISyntaxException {
+    return successReplicationStatus(
+        remote, project, when, ReplicationStatus.ReplicationStatusResult.SUCCEEDED);
+  }
+
+  private String scheduledReplicationStatus(String remote, Project.NameKey project, long when)
+      throws URISyntaxException {
+    return successReplicationStatus(
+        remote, project, when, ReplicationStatus.ReplicationStatusResult.SCHEDULED);
+  }
+
+  private String successReplicationStatus(
+      String remote,
+      Project.NameKey project,
+      long when,
+      ReplicationStatus.ReplicationStatusResult replicationStatusResult)
+      throws URISyntaxException {
     return projectReplicationStatus(
         remote,
         project,
         when,
         ProjectReplicationStatus.ProjectReplicationStatusResult.OK,
-        ReplicationStatus.ReplicationStatusResult.SUCCEEDED);
+        replicationStatusResult);
   }
 
   private String failedReplicationStatus(String remote, Project.NameKey project, long when)