azkaban-aplcache

flow trigger/dependency instance (#1611) PR added two core

1/23/2018 9:18:32 PM

Details

diff --git a/azkaban-web-server/src/main/java/azkaban/flowtrigger/CancellationCause.java b/azkaban-web-server/src/main/java/azkaban/flowtrigger/CancellationCause.java
new file mode 100644
index 0000000..9cc5aae
--- /dev/null
+++ b/azkaban-web-server/src/main/java/azkaban/flowtrigger/CancellationCause.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2017 LinkedIn Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package azkaban.flowtrigger;
+
+public enum CancellationCause {
+  NONE, //no cancellation occurred
+  TIMEOUT, // cancellation is issued due to exceeding max wait time
+  MANUAL, // cancellation is issued by user
+  FAILURE, // cancellation is issued by dependency instance failure
+  CASCADING // cancelled by cascading failure
+}
diff --git a/azkaban-web-server/src/main/java/azkaban/flowtrigger/DependencyInstance.java b/azkaban-web-server/src/main/java/azkaban/flowtrigger/DependencyInstance.java
new file mode 100644
index 0000000..d03968c
--- /dev/null
+++ b/azkaban-web-server/src/main/java/azkaban/flowtrigger/DependencyInstance.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2017 LinkedIn Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package azkaban.flowtrigger;
+
+import java.util.Date;
+
+public class DependencyInstance {
+
+  private final Date startTime;
+  private final String depName;
+  private TriggerInstance triggerInstance;
+  private DependencyInstanceContext context;
+  private volatile Date endTime;
+  private volatile Status status;
+  private volatile CancellationCause cause;
+
+  //todo chengren311: convert it to builder
+  public DependencyInstance(final String depName, final Date startTime,
+      final Date endTime, final DependencyInstanceContext context, final Status status,
+      final CancellationCause cause) {
+    this.status = status;
+    this.depName = depName;
+    this.startTime = startTime;
+    this.endTime = endTime;
+    this.context = context;
+    this.cause = cause;
+  }
+
+  public CancellationCause getCancellationCause() {
+    return this.cause;
+  }
+
+  public void setCancellationCause(final CancellationCause cancellationCause) {
+    this.cause = cancellationCause;
+  }
+
+  public TriggerInstance getTriggerInstance() {
+    return this.triggerInstance;
+  }
+
+  public void setTriggerInstance(final TriggerInstance triggerInstance) {
+    this.triggerInstance = triggerInstance;
+  }
+
+  public void setDependencyInstanceContext(final DependencyInstanceContext context) {
+    this.context = context;
+  }
+
+  public Date getStartTime() {
+    return this.startTime;
+  }
+
+  public Date getEndTime() {
+    return this.endTime;
+  }
+
+  public void setEndTime(final Date endTime) {
+    this.endTime = endTime;
+  }
+
+  public String getDepName() {
+    return this.depName;
+  }
+
+  public DependencyInstanceContext getContext() {
+    return this.context;
+  }
+
+  public Status getStatus() {
+    return this.status;
+  }
+
+  public void setStatus(final Status status) {
+    this.status = status;
+  }
+
+}
diff --git a/azkaban-web-server/src/main/java/azkaban/flowtrigger/Status.java b/azkaban-web-server/src/main/java/azkaban/flowtrigger/Status.java
new file mode 100644
index 0000000..3862c7b
--- /dev/null
+++ b/azkaban-web-server/src/main/java/azkaban/flowtrigger/Status.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2017 LinkedIn Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package azkaban.flowtrigger;
+
+import com.google.common.collect.ImmutableSet;
+import java.util.Set;
+
+/**
+ * Represents status for trigger/dependency
+ */
+public enum Status {
+  RUNNING, // dependency instance is running
+  SUCCEEDED, // dependency instance succeeds
+  CANCELLED, // dependency instance is cancelled
+  CANCELLING; // dependency instance is being cancelled
+
+  public static boolean isDone(final Status status) {
+    final Set<Status> terminalStatus = ImmutableSet.of(SUCCEEDED, CANCELLED);
+    return terminalStatus.contains(status);
+  }
+}
diff --git a/azkaban-web-server/src/main/java/azkaban/flowtrigger/TriggerInstance.java b/azkaban-web-server/src/main/java/azkaban/flowtrigger/TriggerInstance.java
new file mode 100644
index 0000000..592aa55
--- /dev/null
+++ b/azkaban-web-server/src/main/java/azkaban/flowtrigger/TriggerInstance.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2017 LinkedIn Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package azkaban.flowtrigger;
+
+import azkaban.project.FlowTrigger;
+import azkaban.project.Project;
+import com.google.common.collect.ImmutableList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+public class TriggerInstance {
+
+  private final List<DependencyInstance> depInstances;
+  private final String id;
+  private final String submitUser;
+  private final Project project;
+  private final String flowId;
+  private final int flowVersion;
+  private FlowTrigger flowTrigger;
+  private volatile int flowExecId; // associated flow execution id
+
+  //todo chengren311: convert it to builder
+  public TriggerInstance(final String id, final FlowTrigger flowTrigger, final String flowId,
+      final int flowVersion, final String submitUser, final List<DependencyInstance> depInstances,
+      final int flowExecId, final Project project) {
+    this.depInstances = ImmutableList.copyOf(depInstances);
+    this.id = id;
+    this.flowTrigger = flowTrigger;
+    this.submitUser = submitUser;
+    this.flowId = flowId;
+    this.flowVersion = flowVersion;
+    this.flowExecId = flowExecId;
+    this.project = project;
+    for (final DependencyInstance depInst : this.depInstances) {
+      depInst.setTriggerInstance(this);
+    }
+  }
+
+  public Project getProject() {
+    return this.project;
+  }
+
+  public String getProjectName() {
+    return this.project.getName();
+  }
+
+  public List<String> getFailureEmails() {
+    return this.project.getFlow(this.getFlowId()).getFailureEmails();
+  }
+
+  public String getFlowId() {
+    return this.flowId;
+  }
+
+  public int getFlowVersion() {
+    return this.flowVersion;
+  }
+
+  public int getFlowExecId() {
+    return this.flowExecId;
+  }
+
+  public void setFlowExecId(final int flowExecId) {
+    this.flowExecId = flowExecId;
+  }
+
+  public final FlowTrigger getFlowTrigger() {
+    return this.flowTrigger;
+  }
+
+  public void setFlowTrigger(final FlowTrigger flowTrigger) {
+    this.flowTrigger = flowTrigger;
+  }
+
+  public String getSubmitUser() {
+    return this.submitUser;
+  }
+
+  public void addDependencyInstance(final DependencyInstance depInst) {
+    this.depInstances.add(depInst);
+  }
+
+  public List<DependencyInstance> getDepInstances() {
+    return this.depInstances;
+  }
+
+  public String getId() {
+    return this.id;
+  }
+
+  private boolean isRunning(final Set<Status> statuses) {
+    if (statuses.contains(Status.RUNNING)) {
+      for (final Status status : statuses) {
+        if (!status.equals(Status.SUCCEEDED) && !status.equals(Status.RUNNING)) {
+          return false;
+        }
+      }
+      return true;
+    }
+    return false;
+  }
+
+  private boolean isSucceed(final Set<Status> statuses) {
+    return statuses.contains(Status.SUCCEEDED) && statuses.size() == 1;
+  }
+
+  private boolean isCancelled(final Set<Status> statuses) {
+    if (statuses.contains(Status.CANCELLED)) {
+      for (final Status status : statuses) {
+        if (!status.equals(Status.SUCCEEDED) && !status.equals(Status.CANCELLED)) {
+          return false;
+        }
+      }
+      return true;
+    }
+    return false;
+  }
+
+  public Status getStatus() {
+    // no-dependency trigger is always considered as success
+    if (this.depInstances.isEmpty()) {
+      return Status.SUCCEEDED;
+    }
+    final Set<Status> statusSet = new HashSet<>();
+
+    for (final DependencyInstance depInst : this.depInstances) {
+      statusSet.add(depInst.getStatus());
+    }
+
+    if (isRunning(statusSet)) {
+      return Status.RUNNING;
+    } else if (isSucceed(statusSet)) {
+      return Status.SUCCEEDED;
+    } else if (isCancelled(statusSet)) {
+      return Status.CANCELLED;
+    } else {
+      return Status.CANCELLING;
+    }
+  }
+
+  public Date getStartTime() {
+    final List<Date> startTimeList = this.depInstances.stream()
+        .map(DependencyInstance::getStartTime).collect(Collectors.toList());
+    return startTimeList.isEmpty() ? null : Collections.min(startTimeList);
+  }
+
+  public Date getEndTime() {
+    if (Status.isDone(this.getStatus())) {
+      final List<Date> endTimeList = this.depInstances.stream()
+          .map(DependencyInstance::getEndTime).filter(endTime -> endTime != null)
+          .collect(Collectors.toList());
+      return endTimeList.isEmpty() ? null : Collections.max(endTimeList);
+    } else {
+      return null;
+    }
+  }
+}
diff --git a/azkaban-web-server/src/test/java/azkaban/flowtrigger/TriggerInstanceTest.java b/azkaban-web-server/src/test/java/azkaban/flowtrigger/TriggerInstanceTest.java
new file mode 100644
index 0000000..468026a
--- /dev/null
+++ b/azkaban-web-server/src/test/java/azkaban/flowtrigger/TriggerInstanceTest.java
@@ -0,0 +1,306 @@
+/*
+ * Copyright 2017 LinkedIn Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package azkaban.flowtrigger;
+
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import org.junit.Test;
+
+public class TriggerInstanceTest {
+
+  public static Date getDate(final int hour, final int minute, final int second) {
+    final Calendar cal = Calendar.getInstance();
+    cal.set(Calendar.YEAR, 2000);
+    cal.set(Calendar.MONTH, 1);
+    cal.set(Calendar.DAY_OF_MONTH, 1);
+    cal.set(Calendar.HOUR_OF_DAY, hour);
+    cal.set(Calendar.MINUTE, minute);
+    cal.set(Calendar.SECOND, second);
+    cal.set(Calendar.MILLISECOND, 0);
+    return cal.getTime();
+  }
+
+  private DependencyInstance createTestDependencyInstance(final Status status,
+      final CancellationCause killingCause) {
+    final DependencyInstance depInst = new DependencyInstance(null, null, null, null, null,
+        null);
+    depInst.setStatus(status);
+    depInst.setCancellationCause(killingCause);
+    return depInst;
+  }
+
+  private DependencyInstance createTestDependencyInstance(final Status status,
+      final CancellationCause cancelCause, final Date startTime, final Date endTime) {
+    final DependencyInstance depInst = new DependencyInstance(null, startTime, endTime, null,
+        status, cancelCause);
+    depInst.setStatus(status);
+    depInst.setCancellationCause(cancelCause);
+    return depInst;
+  }
+
+  @Test
+  public void testTriggerInstanceStartTime() throws Exception {
+    final List<DependencyInstance> dependencyInstanceList = new ArrayList<>();
+    Date expectedStartTime = getDate(2, 2, 2);
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.SUCCEEDED, CancellationCause.NONE, getDate(2, 2,
+            2), getDate(2, 2, 3)));
+
+    TriggerInstance ti = null;
+    ti = new TriggerInstance("1", null, "1", 1,
+        "test", dependencyInstanceList, -1, null);
+    assertThat(ti.getStartTime()).isEqualTo(expectedStartTime);
+    dependencyInstanceList.clear();
+
+    ti = new TriggerInstance("1", null, "1", 1,
+        "test", dependencyInstanceList, -1, null);
+    assertThat(ti.getStartTime()).isNull();
+    dependencyInstanceList.clear();
+
+    expectedStartTime = getDate(2, 2, 2);
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.SUCCEEDED, CancellationCause.NONE, getDate(2, 2,
+            4), getDate(2, 2, 3)));
+
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.SUCCEEDED, CancellationCause.NONE, getDate(2, 2,
+            3), getDate(2, 2, 3)));
+
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.SUCCEEDED, CancellationCause.NONE, getDate(2, 2,
+            2), getDate(2, 2, 3)));
+
+    ti = new TriggerInstance("1", null, "1", 1,
+        "test", dependencyInstanceList, -1, null);
+    assertThat(ti.getStartTime()).isEqualTo(expectedStartTime);
+  }
+
+  @Test
+  public void testTriggerInstanceEndTime() throws Exception {
+    final List<DependencyInstance> dependencyInstanceList = new ArrayList<>();
+    Date expectedEndTime = getDate(3, 2, 3);
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.SUCCEEDED, CancellationCause.NONE, getDate(2, 2,
+            2), getDate(3, 2, 3)));
+
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.SUCCEEDED, CancellationCause.NONE, getDate(2, 2,
+            2), getDate(2, 2, 3)));
+
+    TriggerInstance ti = null;
+    ti = new TriggerInstance("1", null, "1", 1,
+        "test", dependencyInstanceList, -1, null);
+    assertThat(ti.getEndTime()).isEqualTo(expectedEndTime);
+    dependencyInstanceList.clear();
+
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.RUNNING, CancellationCause.NONE, getDate(2, 2,
+            2), null));
+
+    ti = new TriggerInstance("1", null, "1", 1,
+        "test", dependencyInstanceList, -1, null);
+    assertThat(ti.getEndTime()).isNull();
+    dependencyInstanceList.clear();
+
+    expectedEndTime = getDate(3, 2, 3);
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.SUCCEEDED, CancellationCause.NONE, getDate(2, 2,
+            3), null));
+
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.SUCCEEDED, CancellationCause.NONE, getDate(3, 2,
+            2), null));
+
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.SUCCEEDED, CancellationCause.NONE, getDate(2, 2,
+            2), expectedEndTime));
+    ti = new TriggerInstance("1", null, "1", 1,
+        "test", dependencyInstanceList, -1, null);
+    assertThat(ti.getEndTime()).isEqualTo(expectedEndTime);
+    dependencyInstanceList.clear();
+
+    ti = new TriggerInstance("1", null, "1", 1,
+        "test", dependencyInstanceList, -1, null);
+    assertThat(ti.getEndTime()).isNull();
+    dependencyInstanceList.clear();
+  }
+
+  @Test
+  public void testTriggerInstanceRunningStatus() throws Exception {
+    final List<DependencyInstance> dependencyInstanceList = new ArrayList<>();
+    TriggerInstance ti = null;
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.RUNNING, CancellationCause.MANUAL));
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.SUCCEEDED, CancellationCause.NONE));
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.SUCCEEDED, CancellationCause.NONE));
+
+    ti = new TriggerInstance("1", null,
+        "1", 1, "test", dependencyInstanceList,
+        -1, null);
+    assertThat(ti.getStatus()).isEqualTo(Status.RUNNING);
+    dependencyInstanceList.clear();
+
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.RUNNING, CancellationCause.MANUAL));
+
+    ti = new TriggerInstance("1", null,
+        "1", 1, "test", dependencyInstanceList,
+        -1, null);
+    assertThat(ti.getStatus()).isEqualTo(Status.RUNNING);
+    dependencyInstanceList.clear();
+  }
+
+  @Test
+  public void testTriggerInstanceSucceededStatus() throws Exception {
+    final List<DependencyInstance> dependencyInstanceList = new ArrayList<>();
+    TriggerInstance ti = null;
+
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.SUCCEEDED, CancellationCause.NONE));
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.SUCCEEDED, CancellationCause.NONE));
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.SUCCEEDED, CancellationCause.NONE));
+
+    ti = new TriggerInstance("1", null,
+        "1", 1, "test", dependencyInstanceList,
+        -1, null);
+    assertThat(ti.getStatus()).isEqualTo(Status.SUCCEEDED);
+    dependencyInstanceList.clear();
+
+    ti = new TriggerInstance("1", null,
+        "1", 1, "test", dependencyInstanceList,
+        -1, null);
+    assertThat(ti.getStatus()).isEqualTo(Status.SUCCEEDED);
+    dependencyInstanceList.clear();
+  }
+
+  @Test
+  public void testTriggerInstanceCancellingStatus() throws Exception {
+    final List<DependencyInstance> dependencyInstanceList = new ArrayList<>();
+    TriggerInstance ti = null;
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.CANCELLING, CancellationCause.MANUAL));
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.CANCELLED, CancellationCause.MANUAL));
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.SUCCEEDED, CancellationCause.NONE));
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.SUCCEEDED, CancellationCause.NONE));
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.SUCCEEDED, CancellationCause.NONE));
+
+    ti = new TriggerInstance("1", null,
+        "1", 1, "test", dependencyInstanceList,
+        -1, null);
+    assertThat(ti.getStatus()).isEqualTo(Status.CANCELLING);
+    dependencyInstanceList.clear();
+
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.RUNNING, CancellationCause.MANUAL));
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.CANCELLED, CancellationCause.MANUAL));
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.SUCCEEDED, CancellationCause.NONE));
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.SUCCEEDED, CancellationCause.NONE));
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.SUCCEEDED, CancellationCause.NONE));
+
+    ti = new TriggerInstance("1", null,
+        "1", 1, "test", dependencyInstanceList,
+        -1, null);
+    assertThat(ti.getStatus()).isEqualTo(Status.CANCELLING);
+    dependencyInstanceList.clear();
+
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.CANCELLED, CancellationCause.MANUAL));
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.CANCELLING, CancellationCause.NONE));
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.RUNNING, CancellationCause.NONE));
+
+    ti = new TriggerInstance("1", null,
+        "1", 1, "test", dependencyInstanceList,
+        -1, null);
+    assertThat(ti.getStatus()).isEqualTo(Status.CANCELLING);
+    dependencyInstanceList.clear();
+
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.RUNNING, CancellationCause.MANUAL));
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.CANCELLING, CancellationCause.MANUAL));
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.SUCCEEDED, CancellationCause.NONE));
+
+    ti = new TriggerInstance("1", null,
+        "1", 1, "test", dependencyInstanceList,
+        -1, null);
+    assertThat(ti.getStatus()).isEqualTo(Status.CANCELLING);
+    dependencyInstanceList.clear();
+
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.CANCELLED, CancellationCause.MANUAL));
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.RUNNING, CancellationCause.NONE));
+
+    ti = new TriggerInstance("1", null,
+        "1", 1, "test", dependencyInstanceList,
+        -1, null);
+    assertThat(ti.getStatus()).isEqualTo(Status.CANCELLING);
+    dependencyInstanceList.clear();
+  }
+
+  @Test
+  public void testTriggerInstanceCancelledStatus() throws Exception {
+    final List<DependencyInstance> dependencyInstanceList = new ArrayList<>();
+    TriggerInstance ti = null;
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.CANCELLED, CancellationCause.MANUAL));
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.CANCELLED, CancellationCause.MANUAL));
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.SUCCEEDED, CancellationCause.NONE));
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.SUCCEEDED, CancellationCause.NONE));
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.SUCCEEDED, CancellationCause.NONE));
+
+    ti = new TriggerInstance("1", null, "1", 1,
+        "test", dependencyInstanceList, -1, null);
+
+    assertThat(ti.getStatus()).isEqualTo(Status.CANCELLED);
+    dependencyInstanceList.clear();
+
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.CANCELLED, CancellationCause.MANUAL));
+    dependencyInstanceList
+        .add(createTestDependencyInstance(Status.CANCELLED, CancellationCause.MANUAL));
+
+    ti = new TriggerInstance("1", null, "1", 1,
+        "test", dependencyInstanceList, -1, null);
+    assertThat(ti.getStatus()).isEqualTo(Status.CANCELLED);
+    dependencyInstanceList.clear();
+  }
+
+}