content: /*
   * Copyright 2010-2025 Hyland Software, Inc. and its affiliates.
   *
   * 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 org.activiti.engine.test.api.v6;
  
  import static org.assertj.core.api.Assertions.assertThat;
  
  import java.util.ArrayList;
  import java.util.List;
  import org.activiti.engine.delegate.event.ActivitiActivityCancelledEvent;
  import org.activiti.engine.delegate.event.ActivitiActivityEvent;
  import org.activiti.engine.delegate.event.ActivitiEvent;
  import org.activiti.engine.delegate.event.ActivitiEventListener;
  import org.activiti.engine.history.HistoricActivityInstance;
  import org.activiti.engine.impl.history.HistoryLevel;
  import org.activiti.engine.impl.test.PluggableActivitiTestCase;
  import org.activiti.engine.runtime.Execution;
  import org.activiti.engine.runtime.ProcessInstance;
  import org.activiti.engine.task.Task;
  import org.activiti.engine.test.Deployment;
  import org.junit.Test;
  
  public class Activiti6ExecutionTest extends PluggableActivitiTestCase {
  
      @Test
      @Deployment
      public void testOneTaskProcess() {
          ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("oneTaskProcess");
  
          List<Execution> executionList = runtimeService
              .createExecutionQuery()
              .processInstanceId(processInstance.getId())
              .list();
          assertThat(executionList).hasSize(2);
  
          Execution rootProcessInstance = null;
          Execution childExecution = null;
  
          for (Execution execution : executionList) {
              if (execution.getId().equals(execution.getProcessInstanceId())) {
                  rootProcessInstance = execution;
  
                  assertThat(execution.getActivityId()).isNull();
              } else {
                  childExecution = execution;
  
                  assertThat(execution.getId()).isNotEqualTo(execution.getProcessInstanceId());
                  assertThat(execution.getActivityId()).isEqualTo("theTask");
              }
          }
  
          assertThat(rootProcessInstance).isNotNull();
          assertThat(childExecution).isNotNull();
  
          Task task = taskService.createTaskQuery().singleResult();
          assertThat(task.getExecutionId()).isEqualTo(childExecution.getId());
  
          taskService.complete(task.getId());
  
          if (processEngineConfiguration.getHistoryLevel().isAtLeast(HistoryLevel.ACTIVITY)) {
              List<HistoricActivityInstance> historicActivities = historyService
                  .createHistoricActivityInstanceQuery()
                  .processInstanceId(processInstance.getId())
                  .list();
              assertThat(historicActivities).hasSize(3);
  
              List<String> activityIds = new ArrayList<String>();
              activityIds.add("theStart");
              activityIds.add("theTask");
              activityIds.add("theEnd");
  
              for (HistoricActivityInstance historicActivityInstance : historicActivities) {
                  activityIds.remove(historicActivityInstance.getActivityId());
                  assertThat(historicActivityInstance.getExecutionId()).isEqualTo(childExecution.getId());
              }
  
              assertThat(activityIds).hasSize(0);
          }
      }
  
      @Test
      @Deployment
      public void testOneNestedTaskProcess() {
          ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("oneNestedTaskProcess");
  
          List<Execution> executionList = runtimeService
              .createExecutionQuery()
              .processInstanceId(processInstance.getId())
              .list();
          assertThat(executionList).hasSize(2);
  
          Execution rootProcessInstance = null;
          Execution childExecution = null;
  
          for (Execution execution : executionList) {
              if (execution.getId().equals(execution.getProcessInstanceId())) {
                  rootProcessInstance = execution;
  
                  assertThat(execution.getActivityId()).isNull();
              } else {
                  childExecution = execution;
  
                  assertThat(execution.getId()).isNotEqualTo(execution.getProcessInstanceId());
                  assertThat(execution.getActivityId()).isEqualTo("theTask1");
              }
          }
  
          assertThat(rootProcessInstance).isNotNull();
          assertThat(childExecution).isNotNull();
  
          Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
          assertThat(task.getExecutionId()).isEqualTo(childExecution.getId());
  
          taskService.complete(task.getId());
  
          executionList = runtimeService.createExecutionQuery().processInstanceId(processInstance.getId()).list();
          assertThat(executionList).hasSize(3);
  
          task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
          assertThat(task.getTaskDefinitionKey()).isEqualTo("subTask");
          Execution subTaskExecution = runtimeService
              .createExecutionQuery()
              .executionId(task.getExecutionId())
              .singleResult();
          assertThat(subTaskExecution.getActivityId()).isEqualTo("subTask");
  
          Execution subProcessExecution = runtimeService
              .createExecutionQuery()
              .executionId(subTaskExecution.getParentId())
              .singleResult();
          assertThat(subProcessExecution.getActivityId()).isEqualTo("subProcess");
          assertThat(subProcessExecution.getParentId()).isEqualTo(rootProcessInstance.getId());
  
          taskService.complete(task.getId());
  
          executionList = runtimeService.createExecutionQuery().processInstanceId(processInstance.getId()).list();
          assertThat(executionList).hasSize(2);
  
          task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
          assertThat(childExecution.getId()).isNotEqualTo(task.getExecutionId());
  
          Execution finalTaskExecution = runtimeService
              .createExecutionQuery()
              .executionId(task.getExecutionId())
              .singleResult();
          assertThat(finalTaskExecution.getActivityId()).isEqualTo("theTask2");
  
          assertThat(finalTaskExecution.getParentId()).isEqualTo(rootProcessInstance.getId());
  
          taskService.complete(task.getId());
  
          assertProcessEnded(processInstance.getId());
  
          if (processEngineConfiguration.getHistoryLevel().isAtLeast(HistoryLevel.ACTIVITY)) {
              List<HistoricActivityInstance> historicActivities = historyService
                  .createHistoricActivityInstanceQuery()
                  .processInstanceId(processInstance.getId())
                  .list();
              assertThat(historicActivities).hasSize(8);
  
              List<String> activityIds = new ArrayList<String>();
              activityIds.add("theStart");
              activityIds.add("theTask1");
              activityIds.add("subProcess");
              activityIds.add("subStart");
              activityIds.add("subTask");
              activityIds.add("subEnd");
              activityIds.add("theTask2");
              activityIds.add("theEnd");
  
              for (HistoricActivityInstance historicActivityInstance : historicActivities) {
                  String activityId = historicActivityInstance.getActivityId();
                  activityIds.remove(activityId);
  
                  if ("theStart".equalsIgnoreCase(activityId) || "theTask1".equalsIgnoreCase(activityId)) {
                      assertThat(historicActivityInstance.getExecutionId()).isEqualTo(childExecution.getId());
                  } else if ("theTask2".equalsIgnoreCase(activityId) || "theEnd".equalsIgnoreCase(activityId)) {
                      assertThat(historicActivityInstance.getExecutionId()).isEqualTo(finalTaskExecution.getId());
                  } else if (
                      "subStart".equalsIgnoreCase(activityId) ||
                      "subTask".equalsIgnoreCase(activityId) ||
                      "subEnd".equalsIgnoreCase(activityId)
                  ) {
                      assertThat(historicActivityInstance.getExecutionId()).isEqualTo(subTaskExecution.getId());
                  } else if ("subProcess".equalsIgnoreCase(activityId)) {
                      assertThat(historicActivityInstance.getExecutionId()).isEqualTo(subProcessExecution.getId());
                  }
              }
  
              assertThat(activityIds).hasSize(0);
          }
      }
  
      @Test
      @Deployment
      public void testSubProcessWithTimer() {
          ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("subProcessWithTimer");
  
          List<Execution> executionList = runtimeService
              .createExecutionQuery()
              .processInstanceId(processInstance.getId())
              .list();
          assertThat(executionList).hasSize(2);
  
          Execution rootProcessInstance = null;
          Execution childExecution = null;
  
          for (Execution execution : executionList) {
              if (execution.getId().equals(execution.getProcessInstanceId())) {
                  rootProcessInstance = execution;
  
                  assertThat(execution.getActivityId()).isNull();
              } else {
                  childExecution = execution;
  
                  assertThat(execution.getActivityId()).isEqualTo("theTask1");
              }
          }
  
          assertThat(rootProcessInstance).isNotNull();
          assertThat(childExecution).isNotNull();
  
          Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
          assertThat(task.getExecutionId()).isEqualTo(childExecution.getId());
  
          taskService.complete(task.getId());
  
          executionList = runtimeService.createExecutionQuery().processInstanceId(processInstance.getId()).list();
          assertThat(executionList).hasSize(4);
  
          task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
          assertThat(task.getTaskDefinitionKey()).isEqualTo("subTask");
          Execution subTaskExecution = runtimeService
              .createExecutionQuery()
              .executionId(task.getExecutionId())
              .singleResult();
          assertThat(subTaskExecution.getActivityId()).isEqualTo("subTask");
  
          Execution subProcessExecution = runtimeService
              .createExecutionQuery()
              .executionId(subTaskExecution.getParentId())
              .singleResult();
          assertThat(subProcessExecution.getActivityId()).isEqualTo("subProcess");
          assertThat(subProcessExecution.getParentId()).isEqualTo(rootProcessInstance.getId());
  
          taskService.complete(task.getId());
  
          executionList = runtimeService.createExecutionQuery().processInstanceId(processInstance.getId()).list();
          assertThat(executionList).hasSize(2);
  
          task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
          assertThat(childExecution.getId()).isNotEqualTo(task.getExecutionId());
  
          Execution finalTaskExecution = runtimeService
              .createExecutionQuery()
              .executionId(task.getExecutionId())
              .singleResult();
          assertThat(finalTaskExecution.getActivityId()).isEqualTo("theTask2");
  
          assertThat(finalTaskExecution.getParentId()).isEqualTo(rootProcessInstance.getId());
  
          taskService.complete(task.getId());
  
          assertProcessEnded(processInstance.getId());
  
          if (processEngineConfiguration.getHistoryLevel().isAtLeast(HistoryLevel.ACTIVITY)) {
              List<HistoricActivityInstance> historicActivities = historyService
                  .createHistoricActivityInstanceQuery()
                  .processInstanceId(processInstance.getId())
                  .list();
              assertThat(historicActivities).hasSize(8);
  
              List<String> activityIds = new ArrayList<String>();
              activityIds.add("theStart");
              activityIds.add("theTask1");
              activityIds.add("subProcess");
              activityIds.add("subStart");
              activityIds.add("subTask");
              activityIds.add("subEnd");
              activityIds.add("theTask2");
              activityIds.add("theEnd");
  
              for (HistoricActivityInstance historicActivityInstance : historicActivities) {
                  String activityId = historicActivityInstance.getActivityId();
                  activityIds.remove(activityId);
  
                  if ("theStart".equalsIgnoreCase(activityId) || "theTask1".equalsIgnoreCase(activityId)) {
                      assertThat(historicActivityInstance.getExecutionId()).isEqualTo(childExecution.getId());
                  } else if ("theTask2".equalsIgnoreCase(activityId) || "theEnd".equalsIgnoreCase(activityId)) {
                      assertThat(historicActivityInstance.getExecutionId()).isEqualTo(finalTaskExecution.getId());
                  } else if (
                      "subStart".equalsIgnoreCase(activityId) ||
                      "subTask".equalsIgnoreCase(activityId) ||
                      "subEnd".equalsIgnoreCase(activityId)
                  ) {
                      assertThat(historicActivityInstance.getExecutionId()).isEqualTo(subTaskExecution.getId());
                  } else if ("subProcess".equalsIgnoreCase(activityId)) {
                      assertThat(historicActivityInstance.getExecutionId()).isEqualTo(subProcessExecution.getId());
                  }
              }
  
              assertThat(activityIds).hasSize(0);
          }
      }
  
      @Test
      @Deployment
      public void testSubProcessEvents() {
          SubProcessEventListener listener = new SubProcessEventListener();
          processEngineConfiguration.getEventDispatcher().addEventListener(listener);
  
          ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("subProcessEvents");
  
          Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
          taskService.complete(task.getId());
  
          Execution subProcessExecution = runtimeService
              .createExecutionQuery()
              .processInstanceId(processInstance.getId())
              .activityId("subProcess")
              .singleResult();
  
          task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
          taskService.complete(task.getId());
  
          task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
          taskService.complete(task.getId());
  
          assertProcessEnded(processInstance.getId());
  
          // Verify Events
          List<ActivitiEvent> events = listener.getEventsReceived();
          assertThat(events).hasSize(2);
  
          ActivitiActivityEvent event = (ActivitiActivityEvent) events.get(0);
          assertThat(event.getActivityType()).isEqualTo("subProcess");
          assertThat(event.getExecutionId()).isEqualTo(subProcessExecution.getId());
  
          event = (ActivitiActivityEvent) events.get(1);
          assertThat(event.getActivityType()).isEqualTo("subProcess");
          assertThat(event.getExecutionId()).isEqualTo(subProcessExecution.getId());
  
          processEngineConfiguration.getEventDispatcher().removeEventListener(listener);
      }
  
      public class SubProcessEventListener implements ActivitiEventListener {
  
          private List<ActivitiEvent> eventsReceived;
  
          public SubProcessEventListener() {
              eventsReceived = new ArrayList<ActivitiEvent>();
          }
  
          public List<ActivitiEvent> getEventsReceived() {
              return eventsReceived;
          }
  
          public void clearEventsReceived() {
              eventsReceived.clear();
          }
  
          @Override
          public void onEvent(ActivitiEvent activitiEvent) {
              if (activitiEvent instanceof ActivitiActivityEvent) {
                  ActivitiActivityEvent event = (ActivitiActivityEvent) activitiEvent;
                  if ("subProcess".equals(event.getActivityType())) {
                      eventsReceived.add(event);
                  }
              } else if (activitiEvent instanceof ActivitiActivityCancelledEvent) {
                  ActivitiActivityCancelledEvent event = (ActivitiActivityCancelledEvent) activitiEvent;
                  if ("subProcess".equals(event.getActivityType())) {
                      eventsReceived.add(event);
                  }
              }
          }
  
          @Override
          public boolean isFailOnException() {
              return true;
          }
      }
  }
  