Make it possible to re-create ArtifactCreated events

This change add a force flag, which when is true make it possible to
create ArtifactCreated event for reused tags. This flag can only be
used when creating events through the REST endpoints.

The creation of ArtifactCreated event is also changed sligthly.
Before we always checked if there already was a CD and if there was
we used it. Now we skip this check and always create a new CD for
each new ArtifactCreated event. It should not matter much because if
we create a new ArtifactCreated event there should almost never be a
CD we can reuse(an exception is if Gerrit crash directly after a CD
creation).

Solves: Jira GER-1573
Change-Id: I6622fa714a99aaa1a121cedfdf3b567d435ebc4f
diff --git a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/EiffelEventHub.java b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/EiffelEventHub.java
index 0dd782e..8d6cab9 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/EiffelEventHub.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/EiffelEventHub.java
@@ -50,7 +50,7 @@
    *
    * <p>{@code EventKey.fromEvent(this).equals(EventKey.fromEvent(existing)}
    *
-   * <p>is true
+   * <p>is true and force is set to false
    *
    * <p><b>NOTE:</b>
    *
@@ -58,9 +58,10 @@
    * used after adding the event to this hub.
    *
    * @param event
+   * @param force Create the event even if there already exists an event with an identical key.
    * @throws InterruptedException
    */
-  public void push(EiffelEvent event) throws InterruptedException;
+  public void push(EiffelEvent event, boolean force) throws InterruptedException;
   /**
    * If an event exists, already published or awaiting publish in this EiffelEventHub, such that:
    *
diff --git a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/EiffelEventHubImpl.java b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/EiffelEventHubImpl.java
index 37e96b6..259b080 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/EiffelEventHubImpl.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/EiffelEventHubImpl.java
@@ -64,11 +64,14 @@
   }
 
   @Override
-  public void push(EiffelEvent event) throws InterruptedException {
+  public void push(EiffelEvent event, boolean force) throws InterruptedException {
     checkState(event != null, "Event must not be null.");
     checkState(EventKey.isSupported(event), "Unsupported type: " + event.meta.type.name());
 
     EventKey key = EventKey.fromEvent(event);
+    checkState(
+        !force || key.supportsForce(), "This event does not support force: " + key.toString());
+
     final ReentrantLock putLock = this.putLock;
     final ReentrantLock idLookupLock = this.idLookupLock;
     final AtomicInteger count = this.count;
@@ -88,7 +91,7 @@
       }
       idLookupLock.lock();
       try {
-        if (getExistingId(key, true).isPresent()) {
+        if (!force && getExistingId(key, true).isPresent()) {
           logger.atWarning().log("Event %s is already pushed.", key);
           return;
         }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/eiffel/EventKey.java b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/eiffel/EventKey.java
index 21c848e..fe582d4 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/eiffel/EventKey.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/eiffel/EventKey.java
@@ -64,6 +64,16 @@
     return this.equals(fromEvent(event));
   }
 
+  public boolean supportsForce() {
+    switch (type) {
+      case ARTC:
+      case CD:
+        return true;
+      default:
+        return false;
+    }
+  }
+
   @Override
   public String toString() {
     return String.format("%s(%s)", type.name(), type.getType());
diff --git a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/mapping/EiffelEventFactory.java b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/mapping/EiffelEventFactory.java
index 192d6c3..07522fd 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/mapping/EiffelEventFactory.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/mapping/EiffelEventFactory.java
@@ -275,7 +275,7 @@
     return URLEncoder.encode(name, Charsets.UTF_8);
   }
 
-  private String tagPURL(String projectName, String tagName) {
+  public String tagPURL(String projectName, String tagName) {
     return String.format(tagPURLTemplate, projectName, tagName, projectUrl(projectName), tagName);
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/mapping/EiffelEventMapper.java b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/mapping/EiffelEventMapper.java
index 744628d..10c4fa1 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/mapping/EiffelEventMapper.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/mapping/EiffelEventMapper.java
@@ -177,6 +177,10 @@
     return eventFactoryProvider.get().tagCompositionName(projectName);
   }
 
+  public String tagPURL(String projectName, String tagName) {
+    return eventFactoryProvider.get().tagPURL(projectName, tagName);
+  }
+
   private boolean isCurrentPatchsetOf(RevCommit commit, ChangeData change) {
     return change
         .notes()
diff --git a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParser.java b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParser.java
index 5b8677d..771816c 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParser.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParser.java
@@ -213,18 +213,28 @@
     }
   }
 
-  public void createAndScheduleArtc(String projectName, String tagName, Long creationTime) {
-    CompositionDefinedEventKey cd =
-        CompositionDefinedEventKey.create(mapper.tagCompositionName(projectName), tagName);
+  public void createAndScheduleArtc(
+      String projectName, String tagName, Long creationTime, boolean force) {
     try {
-      Optional<UUID> cdId = eventHub.getExistingId(cd);
-      if (cdId.isEmpty()) {
-        /* Cd event is missing, create it first */
-        createAndScheduleCd(projectName, tagName, creationTime);
-        cdId = eventHub.getExistingId(cd);
-      }
-      if (!cdId.isEmpty()) {
-        pushToHub(mapper.toArtc(projectName, tagName, creationTime, cdId.get()));
+      CompositionDefinedEventKey cd =
+          CompositionDefinedEventKey.create(mapper.tagCompositionName(projectName), tagName);
+      Optional<UUID> oldCdId = eventHub.getExistingId(cd);
+      if (oldCdId.isEmpty() || force) {
+        createAndScheduleCd(projectName, tagName, creationTime, force);
+        Optional<UUID> cdId = eventHub.getExistingId(cd);
+        if (cdId.isPresent() && !cdId.equals(oldCdId)) {
+          pushToHub(mapper.toArtc(projectName, tagName, creationTime, cdId.get()), force);
+          if (oldCdId.isPresent()) {
+            logger.atInfo().log(
+                "Event Artc has been forcibly created for: %s, %s", projectName, tagName);
+          } else {
+            logger.atFine().log("Event Artc has been created for: %s, %s", projectName, tagName);
+          }
+        }
+      } else {
+        /* Artc event has already been created */
+        logger.atWarning().log(
+            "Event Artc has already been created for: %s, %s", projectName, tagName);
       }
     } catch (EiffelEventIdLookupException | InterruptedException e) {
       logger.atSevere().withCause(e).log(
@@ -232,7 +242,8 @@
     }
   }
 
-  private void createAndScheduleCd(String projectName, String tagName, Long creationTime) {
+  private void createAndScheduleCd(
+      String projectName, String tagName, Long creationTime, boolean force) {
     SourceChangeEventKey scs = null;
     Optional<UUID> scsId = Optional.empty();
 
@@ -263,7 +274,7 @@
         logger.atSevere().log("Could not find SCS for: %s in %s", commitId, projectName);
         return;
       }
-      pushToHub(mapper.toCd(projectName, tagName, creationTime, scsId.get()));
+      pushToHub(mapper.toCd(projectName, tagName, creationTime, scsId.get()), force);
     } catch (EiffelEventIdLookupException | InterruptedException e) {
       logger.atSevere().withCause(e).log(
           "Event creation failed for: %s",
@@ -301,11 +312,15 @@
   }
 
   private void pushToHub(EiffelEvent toPush) throws InterruptedException {
+    pushToHub(toPush, false);
+  }
+
+  private void pushToHub(EiffelEvent toPush, boolean force) throws InterruptedException {
     int failureCount = 0;
     EventKey key = EventKey.fromEvent(toPush);
     while (true) {
       try {
-        eventHub.push(toPush);
+        eventHub.push(toPush, force);
         logger.atFine().log("Successfully pushed %s to EventHub", key);
         return;
       } catch (InterruptedException e) {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParsingQueue.java b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParsingQueue.java
index 7d57e58..1fd7ec5 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParsingQueue.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParsingQueue.java
@@ -146,27 +146,30 @@
     scheduleArtcCreation(
         event.getProjectName(),
         event.getRefName().substring(RefNames.REFS_TAGS.length()),
-        TimeUtil.nowMs());
+        TimeUtil.nowMs(),
+        false);
   }
 
-  public void scheduleArtcCreation(TagResource resource) {
+  public void scheduleArtcCreation(TagResource resource, boolean force) {
     String tagRef = resource.getRef();
     scheduleArtcCreation(
         resource.getName(),
         tagRef.startsWith(RefNames.REFS_TAGS)
             ? tagRef.substring(RefNames.REFS_TAGS.length())
             : tagRef,
-        resource.getTagInfo().created.getTime());
+        resource.getTagInfo().created.getTime(),
+        force);
   }
 
-  public void scheduleArtcCreation(String projectName, String tagName, Long creationTime) {
+  public void scheduleArtcCreation(
+      String projectName, String tagName, Long creationTime, boolean force) {
     schedule(
         new EventParsingWorker(ARTC, projectName, tagName) {
 
           @Override
           public void doRun() {
             try {
-              eventParser.createAndScheduleArtc(projectName, tagName, creationTime);
+              eventParser.createAndScheduleArtc(projectName, tagName, creationTime, force);
             } catch (Exception e) {
               logger.atSevere().withCause(e).log(
                   "Failed to create ARTC for %s:%s", projectName, tagName);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/rest/CreateArtcs.java b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/rest/CreateArtcs.java
index 0bc0244..9a07c0f 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/rest/CreateArtcs.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/eventseiffel/rest/CreateArtcs.java
@@ -29,7 +29,9 @@
 @Singleton
 @RequiresCapability(GlobalCapability.ADMINISTRATE_SERVER)
 public class CreateArtcs implements RestModifyView<TagResource, CreateArtcs.Input> {
-  static class Input {}
+  static class Input {
+    boolean force;
+  }
 
   private final EiffelEventParsingQueue queue;
 
@@ -41,7 +43,7 @@
   @Override
   public Response<?> apply(TagResource resource, CreateArtcs.Input input)
       throws AuthException, BadRequestException, ResourceConflictException, Exception {
-    queue.scheduleArtcCreation(resource);
+    queue.scheduleArtcCreation(resource, input.force);
     return EventCreationResponse.artc(resource);
   }
 }
diff --git a/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/EiffelEventHubIT.java b/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/EiffelEventHubIT.java
index 3cd4ff0..97febc0 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/EiffelEventHubIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/EiffelEventHubIT.java
@@ -60,7 +60,7 @@
   @Test
   public void eventIsPassedThroughHub() throws Exception {
     EiffelEvent toPublish = TestUtil.newScc();
-    hub.push(toPublish);
+    hub.push(toPublish, false);
     EiffelEvent published = publisher.getPublished(EventKey.fromEvent(toPublish));
     assertNotNull(published);
     assertEquals(toPublish.meta.id, published.meta.id);
@@ -72,7 +72,7 @@
     EventKey key = EventKey.fromEvent(toCheck);
     assertFalse(hub.getExistingId(key).isPresent());
     publisher.stopPublishing();
-    hub.push(toCheck);
+    hub.push(toCheck, false);
     assertTrue(hub.getExistingId(key).isPresent());
     publisher.startPublishing();
     assertTrue(hub.getExistingId(key).isPresent());
@@ -88,7 +88,7 @@
     assertFalse(hub.getScsForCommit(repo, commit, List.of()).isPresent());
     assertEquals(1, TestEventStorage.INSTANCE.queriesForScsIds(repo, commit));
     publisher.stopPublishing();
-    hub.push(toCheck);
+    hub.push(toCheck, false);
     assertFalse(hub.getScsForCommit(repo, commit, List.of()).isPresent());
     assertEquals(2, TestEventStorage.INSTANCE.queriesForScsIds(repo, commit));
     publisher.startPublishing();
@@ -107,7 +107,7 @@
     assertFalse(hub.getScsForCommit(repo, commit, List.of(branch)).isPresent());
     assertEquals(1, TestEventStorage.INSTANCE.queriesForScsIds(repo, commit));
     publisher.stopPublishing();
-    hub.push(toCheck);
+    hub.push(toCheck, false);
     assertTrue(hub.getScsForCommit(repo, commit, List.of(branch)).isPresent());
     assertEquals(1, TestEventStorage.INSTANCE.queriesForScsIds(repo, commit));
     publisher.startPublishing();
@@ -120,7 +120,7 @@
     List<EiffelSourceChangeCreatedEventInfo> toPublish = TestUtil.newSccs(5);
     publisher.stopPublishing();
     for (EiffelEvent event : toPublish) {
-      hub.push(event);
+      hub.push(event, false);
     }
     publisher.startPublishing();
     publisher.assertOrder(toPublish);
@@ -131,8 +131,8 @@
     EiffelSourceChangeCreatedEventInfo event = TestUtil.newScc();
     EiffelEvent sccCopy = TestUtil.copyGitIdentifier(event, SCC);
     assertEquals(EventKey.fromEvent(event), EventKey.fromEvent(sccCopy));
-    hub.push(event);
-    hub.push(sccCopy);
+    hub.push(event, false);
+    hub.push(sccCopy, false);
     EiffelEvent published = publisher.getPublished(EventKey.fromEvent(event));
     assertNotEquals(sccCopy.meta.id, published.meta.id);
     assertEquals(event.meta.id, published.meta.id);
@@ -144,8 +144,8 @@
     EiffelEvent sccCopy = TestUtil.copyGitIdentifier(event, SCC);
     assertEquals(EventKey.fromEvent(event), EventKey.fromEvent(sccCopy));
     publisher.stopPublishing();
-    hub.push(event);
-    hub.push(sccCopy);
+    hub.push(event, false);
+    hub.push(sccCopy, false);
     publisher.startPublishing();
     EiffelEvent published = publisher.getPublished(EventKey.fromEvent(event));
     assertNotEquals(sccCopy.meta.id, published.meta.id);
@@ -156,8 +156,8 @@
   public void eventDoesNotReplaceAlreadyExistingWithDifferentType() throws Exception {
     EiffelSourceChangeCreatedEventInfo event = TestUtil.newScc();
     EiffelEvent scsCopy = TestUtil.copyGitIdentifier(event, SCS);
-    hub.push(event);
-    hub.push(scsCopy);
+    hub.push(event, false);
+    hub.push(scsCopy, false);
     assertNotEquals(scsCopy.meta.id, event.meta.id);
     assertEquals(event.meta.id, publisher.getPublished(EventKey.fromEvent(event)).meta.id);
     assertEquals(scsCopy.meta.id, publisher.getPublished(EventKey.fromEvent(scsCopy)).meta.id);
@@ -168,8 +168,8 @@
     EiffelSourceChangeCreatedEventInfo event = TestUtil.newScc();
     EiffelEvent scsCopy = TestUtil.copyGitIdentifier(event, SCS);
     publisher.stopPublishing();
-    hub.push(event);
-    hub.push(scsCopy);
+    hub.push(event, false);
+    hub.push(scsCopy, false);
     publisher.startPublishing();
     assertNotEquals(scsCopy.meta.id, event.meta.id);
     assertEquals(event.meta.id, publisher.getPublished(EventKey.fromEvent(event)).meta.id);
@@ -180,7 +180,7 @@
   public void idCacheIsUpdatedUponAck() throws Exception {
     publisher.stopPublishing();
     EiffelSourceChangeCreatedEventInfo event = TestUtil.newScc();
-    hub.push(event);
+    hub.push(event, false);
     EventKey key = EventKey.fromEvent(event);
     assertEquals(event.meta.id, hub.getExistingId(key).get());
     assertTrue(idCache.getEventId(key).isEmpty());
diff --git a/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/EiffelEventsTest.java b/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/EiffelEventsTest.java
index b9a8208..8d08ad4 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/EiffelEventsTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/EiffelEventsTest.java
@@ -25,7 +25,7 @@
 import com.google.gerrit.extensions.api.projects.TagInput;
 import com.google.inject.Provider;
 import com.googlesource.gerrit.plugins.eventseiffel.config.EiffelConfig;
-import com.googlesource.gerrit.plugins.eventseiffel.eiffel.CompositionDefinedEventKey;
+import com.googlesource.gerrit.plugins.eventseiffel.eiffel.EventKey;
 import com.googlesource.gerrit.plugins.eventseiffel.eiffel.SourceChangeEventKey;
 import com.googlesource.gerrit.plugins.eventseiffel.eiffel.api.EventStorageException;
 import com.googlesource.gerrit.plugins.eventseiffel.eiffel.dto.EiffelLinkInfo;
@@ -111,7 +111,7 @@
         result.getCommit().getName());
   }
 
-  protected UUID markAsHandled(CompositionDefinedEventKey key) throws EventStorageException {
+  protected UUID markAsHandled(EventKey key) throws EventStorageException {
     Optional<UUID> eventId = TestEventStorage.INSTANCE.getEventId(key);
     if (eventId.isPresent()) {
       return eventId.get();
diff --git a/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/TestEventHub.java b/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/TestEventHub.java
index 4601222..ddbb055 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/TestEventHub.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/TestEventHub.java
@@ -40,13 +40,18 @@
   }
 
   @Override
-  public void push(EiffelEvent event) {
-    EVENTS.add(event);
+  public void push(EiffelEvent event, boolean force) {
+    Optional<EiffelEvent> eventPushed = findEvent(EventKey.fromEvent(event));
+    if (eventPushed.isEmpty()) EVENTS.add(event);
+    else if (force) {
+      EVENTS.remove(eventPushed.get());
+      EVENTS.add(event);
+    }
   }
 
   @Override
   public Optional<UUID> getExistingId(EventKey key) throws EiffelEventIdLookupException {
-    Optional<UUID> eventId = find(key);
+    Optional<UUID> eventId = findId(key);
     if (eventId.isPresent()) {
       return eventId;
     }
@@ -60,20 +65,24 @@
         branches.stream()
             .map(branch -> SourceChangeEventKey.scsKey(repo, branch, commit))
             .collect(Collectors.toList());
-    Optional<UUID> id = keys.stream().map(key -> find(key)).flatMap(Optional::stream).findAny();
+    Optional<UUID> id = keys.stream().map(key -> findId(key)).flatMap(Optional::stream).findAny();
     if (id.isPresent()) return id;
     return idCache.getScsForCommit(repo, commit, branches);
   }
 
-  private Optional<UUID> find(EventKey key) {
+  private Optional<EiffelEvent> findEvent(EventKey key) {
     for (EiffelEvent event : EVENTS) {
       if (key.equals(EventKey.fromEvent(event))) {
-        return Optional.of(event.meta.id);
+        return Optional.of(event);
       }
     }
     return Optional.empty();
   }
 
+  private Optional<UUID> findId(EventKey key) {
+    return findEvent(key).map(event -> event.meta.id);
+  }
+
   @Override
   public Set<EiffelEvent> take(int max) throws InterruptedException {
     return null;
diff --git a/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParserIT.java b/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParserIT.java
index b0ed89b..9ff17be 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParserIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/eventseiffel/parsing/EiffelEventParserIT.java
@@ -201,8 +201,49 @@
   }
 
   @Test
+  public void artcNotRepublishedWithoutForce() throws Exception {
+    String ref = setCdHandled();
+    ArtifactEventKey artc = ArtifactEventKey.create(tagPURL(project.get(), ref));
+    markAsHandled(artc);
+    eventParser.createAndScheduleArtc(project.get(), ref, EPOCH_MILLIS, false);
+    assertEquals(0, TestEventHub.EVENTS.size());
+  }
+
+  @Test
+  public void artcRepublishedWithForce() throws Exception {
+    setScsHandled();
+    String ref =
+        createTagRef(getHead(repo(), "HEAD").getName(), true).substring(Constants.R_TAGS.length());
+    CompositionDefinedEventKey cd =
+        CompositionDefinedEventKey.create(tagCompositionName(project.get()), ref);
+    markAsHandled(cd);
+    ArtifactEventKey artc = ArtifactEventKey.create(tagPURL(project.get(), ref));
+    markAsHandled(artc);
+    eventParser.createAndScheduleArtc(project.get(), ref, EPOCH_MILLIS, true);
+    assertEquals(2, TestEventHub.EVENTS.size());
+    assertCorrectEvent(0, cd);
+    assertCorrectEvent(1, artc);
+  }
+
+  private String setCdHandled() throws Exception {
+    setScsHandled();
+    String ref =
+        createTagRef(getHead(repo(), "HEAD").getName(), true).substring(Constants.R_TAGS.length());
+    CompositionDefinedEventKey cd =
+        CompositionDefinedEventKey.create(tagCompositionName(project.get()), ref);
+    markAsHandled(cd);
+    return ref;
+  }
+
+  private void setScsHandled() throws Exception {
+    SourceChangeEventKey scs =
+        SourceChangeEventKey.scsKey(project.get(), getHead(), getHeadRevision());
+    markAsHandled(scs, getHead(repo(), "HEAD"));
+  }
+
+  @Test
   public void artcQueued() throws Exception {
-    eventParser.createAndScheduleArtc(project.get(), TAG_NAME, EPOCH_MILLIS);
+    eventParser.createAndScheduleArtc(project.get(), TAG_NAME, EPOCH_MILLIS, false);
     assertEquals(0, TestEventHub.EVENTS.size());
   }
 
@@ -218,23 +259,15 @@
 
   @Test
   public void artcQueuedcdHandled() throws Exception {
-    SourceChangeEventKey scs =
-        SourceChangeEventKey.scsKey(project.get(), getHead(), getHeadRevision());
-    markAsHandled(scs, getHead(repo(), "HEAD"));
-    ArtifactEventKey artc = ArtifactEventKey.create(tagPURL(project.get(), TAG_NAME));
-    CompositionDefinedEventKey cd =
-        CompositionDefinedEventKey.create(tagCompositionName(project.get()), TAG_NAME);
-    markAsHandled(cd);
+    String ref = setCdHandled();
+    ArtifactEventKey artc = ArtifactEventKey.create(tagPURL(project.get(), ref));
 
-    eventParser.createAndScheduleArtc(project.get(), TAG_NAME, EPOCH_MILLIS);
-    assertEquals(1, TestEventHub.EVENTS.size());
-    assertCorrectEvent(0, artc);
+    eventParser.createAndScheduleArtc(project.get(), ref, EPOCH_MILLIS, false);
+    assertEquals(0, TestEventHub.EVENTS.size());
   }
 
   private void assertArtcQueuedScsHandled(boolean annotated) throws Exception {
-    SourceChangeEventKey scs =
-        SourceChangeEventKey.scsKey(project.get(), getHead(), getHeadRevision());
-    markAsHandled(scs, getHead(repo(), "HEAD"));
+    setScsHandled();
     String ref =
         createTagRef(getHead(repo(), "HEAD").getName(), annotated)
             .substring(Constants.R_TAGS.length());
@@ -242,7 +275,7 @@
     CompositionDefinedEventKey cd =
         CompositionDefinedEventKey.create(tagCompositionName(project.get()), ref);
 
-    eventParser.createAndScheduleArtc(project.get(), ref, EPOCH_MILLIS);
+    eventParser.createAndScheduleArtc(project.get(), ref, EPOCH_MILLIS, false);
     assertEquals(2, TestEventHub.EVENTS.size());
     assertCorrectEvent(0, cd);
     assertCorrectEvent(1, artc);