// Difference with previous test: now the join will be reached first
  @Deployment(
      resources = {
        "org/camunda/bpm/engine/test/bpmn/event/timer/BoundaryTimerNonInterruptingEventTest.testTimerOnConcurrentTasks.bpmn20.xml"
      })
  public void testTimerOnConcurrentTasks2() {
    String procId =
        runtimeService.startProcessInstanceByKey("nonInterruptingOnConcurrentTasks").getId();
    assertEquals(2, taskService.createTaskQuery().count());

    Job timer = managementService.createJobQuery().singleResult();
    managementService.executeJob(timer.getId());
    assertEquals(3, taskService.createTaskQuery().count());

    // Complete 2 tasks that will trigger the join
    Task task = taskService.createTaskQuery().taskDefinitionKey("firstTask").singleResult();
    taskService.complete(task.getId());
    task = taskService.createTaskQuery().taskDefinitionKey("secondTask").singleResult();
    taskService.complete(task.getId());
    assertEquals(1, taskService.createTaskQuery().count());

    // Finally, complete the task that was created due to the timer
    task = taskService.createTaskQuery().taskDefinitionKey("timerFiredTask").singleResult();
    taskService.complete(task.getId());

    assertProcessEnded(procId);
  }
  @Deployment
  /** see http://jira.codehaus.org/browse/ACT-1173 */
  public void testTimerOnEmbeddedSubprocess() {
    String id =
        runtimeService
            .startProcessInstanceByKey("nonInterruptingTimerOnEmbeddedSubprocess")
            .getId();

    TaskQuery tq = taskService.createTaskQuery().taskAssignee("kermit");

    assertEquals(1, tq.count());

    // Simulate timer
    Job timer = managementService.createJobQuery().singleResult();
    managementService.executeJob(timer.getId());

    tq = taskService.createTaskQuery().taskAssignee("kermit");

    assertEquals(2, tq.count());

    List<Task> tasks = tq.list();

    taskService.complete(tasks.get(0).getId());
    taskService.complete(tasks.get(1).getId());

    assertProcessEnded(id);
  }
  /** starting after a task should not respect that tasks asyncAfter setting */
  @Deployment
  public void testStartAfterAsync() {
    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("exclusiveGateway");
    String processInstanceId = processInstance.getId();

    runtimeService
        .createProcessInstanceModification(processInstance.getId())
        .startAfterActivity("task2")
        .execute();

    // there is now a job for the end event after task2
    Job job = managementService.createJobQuery().singleResult();
    assertNotNull(job);

    Execution jobExecution =
        runtimeService
            .createExecutionQuery()
            .activityId("end2")
            .executionId(job.getExecutionId())
            .singleResult();
    assertNotNull(jobExecution);

    // end process
    completeTasksInOrder("task1");
    managementService.executeJob(job.getId());
    assertProcessEnded(processInstanceId);
  }
  @Deployment(
      resources =
          "org/camunda/bpm/engine/test/bpmn/event/timer/BoundaryTimerNonInterruptingEventTest.testTimerOnConcurrentSubprocess.bpmn20.xml")
  public void testTimerOnConcurrentSubprocess2() {
    String procId =
        runtimeService.startProcessInstanceByKey("testTimerOnConcurrentSubprocess").getId();
    assertEquals(4, taskService.createTaskQuery().count());

    Job timer = managementService.createJobQuery().singleResult();
    managementService.executeJob(timer.getId());
    assertEquals(5, taskService.createTaskQuery().count());

    Task task = taskService.createTaskQuery().taskDefinitionKey("sub1task1").singleResult();
    taskService.complete(task.getId());
    task = taskService.createTaskQuery().taskDefinitionKey("sub1task2").singleResult();
    taskService.complete(task.getId());

    // complete the task that was created due to the timer
    task = taskService.createTaskQuery().taskDefinitionKey("timerFiredTask").singleResult();
    taskService.complete(task.getId());

    task = taskService.createTaskQuery().taskDefinitionKey("sub2task1").singleResult();
    taskService.complete(task.getId());
    task = taskService.createTaskQuery().taskDefinitionKey("sub2task2").singleResult();
    taskService.complete(task.getId());
    assertEquals(0, taskService.createTaskQuery().count());

    assertProcessEnded(procId);
  }
 public void fireTimer(Long helperId, Long eventId) {
   if (helperId == null) {
     throw new ResourcePlanningException("fire timer --> no helper id provided!!");
   }
   if (eventId == null) {
     throw new ResourcePlanningException("fire timer --> no event id provided!!");
   }
   ProcessEngine processEngine = BpmPlatform.getDefaultProcessEngine();
   String businessKey = BusinessKeys.generateRequestHelpBusinessKey(helperId, eventId);
   List<ProcessInstance> executions =
       processEngine
           .getRuntimeService()
           .createProcessInstanceQuery()
           .processInstanceBusinessKey(businessKey)
           .list();
   if ((executions == null) || (executions.size() != 1)) {
     throw new ResourcePlanningException(
         "none or more than one executions found for business key '" + businessKey + "'!!");
   }
   Execution execution = executions.get(0);
   List<Job> jobs =
       processEngine
           .getManagementService()
           .createJobQuery()
           .processInstanceId(execution.getId())
           .list();
   if ((jobs == null) || (jobs.size() == 0)) {
     throw new ResourcePlanningException(
         "no jobs found for execution with business key '" + businessKey + "'!!");
   }
   for (Job job : jobs) {
     processEngine.getManagementService().executeJob(job.getId());
   }
 }
  @Deployment
  public void testJoin() {
    // After process start, there should be 3 timers created
    ProcessInstance pi = runtimeService.startProcessInstanceByKey("testJoin");
    Task task1 = taskService.createTaskQuery().singleResult();
    assertEquals("Main Task", task1.getName());

    Job job = managementService.createJobQuery().processInstanceId(pi.getId()).singleResult();
    assertNotNull(job);

    managementService.executeJob(job.getId());

    // we now have both tasks
    assertEquals(2L, taskService.createTaskQuery().count());

    // end the first
    taskService.complete(task1.getId());

    // we now have one task left
    assertEquals(1L, taskService.createTaskQuery().count());
    Task task2 = taskService.createTaskQuery().singleResult();
    assertEquals("Escalation Task", task2.getName());

    // complete the task, the parallel gateway should fire
    taskService.complete(task2.getId());

    // and the process has ended
    assertProcessEnded(pi.getId());
  }
  @Deployment
  public void testExclusiveJobs() {

    JobDefinition jobDefinition =
        managementService.createJobDefinitionQuery().activityIdIn("task2").singleResult();

    // given that the second task is suspended
    managementService.suspendJobDefinitionById(jobDefinition.getId());

    // if I start a process instance
    runtimeService.startProcessInstanceByKey("testProcess");

    waitForJobExecutorToProcessAllJobs(6000);

    // then the second task is not executed
    assertEquals(1, runtimeService.createProcessInstanceQuery().count());
    // there is a suspended job instance
    Job job = managementService.createJobQuery().singleResult();
    assertEquals(job.getJobDefinitionId(), jobDefinition.getId());
    assertTrue(job.isSuspended());

    // if I unsuspend the job definition, the job is executed:
    managementService.activateJobDefinitionById(jobDefinition.getId(), true);

    waitForJobExecutorToProcessAllJobs(5000);

    assertEquals(0, runtimeService.createProcessInstanceQuery().count());

    // clean up log
    TestHelper.clearOpLog(processEngineConfiguration);
  }
  @Deployment(
      resources = {
        "org/camunda/bpm/engine/test/api/mgmt/ManagementServiceTest.testGetJobExceptionStacktrace.bpmn20.xml"
      })
  public void testSetJobDuedateDateNull() {
    ProcessInstance processInstance =
        runtimeService.startProcessInstanceByKey("exceptionInJobExecution");

    // The execution is waiting in the first usertask. This contains a boundary
    // timer event.
    Job timerJob =
        managementService
            .createJobQuery()
            .processInstanceId(processInstance.getId())
            .singleResult();

    assertNotNull("No job found for process instance", timerJob);
    assertNotNull(timerJob.getDuedate());

    managementService.setJobDuedate(timerJob.getId(), null);

    timerJob =
        managementService
            .createJobQuery()
            .processInstanceId(processInstance.getId())
            .singleResult();

    assertNull(timerJob.getDuedate());
  }
  @Deployment(resources = {"org/camunda/bpm/engine/test/api/mgmt/timerOnTask.bpmn20.xml"})
  public void testDeleteJobThatWasAlreadyAcquired() {
    ClockUtil.setCurrentTime(new Date());

    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("timerOnTask");
    Job timerJob =
        managementService
            .createJobQuery()
            .processInstanceId(processInstance.getId())
            .singleResult();

    // We need to move time at least one hour to make the timer executable
    ClockUtil.setCurrentTime(new Date(ClockUtil.getCurrentTime().getTime() + 7200000L));

    // Acquire job by running the acquire command manually
    ProcessEngineImpl processEngineImpl = (ProcessEngineImpl) processEngine;
    JobExecutor jobExecutor = processEngineImpl.getProcessEngineConfiguration().getJobExecutor();
    AcquireJobsCmd acquireJobsCmd = new AcquireJobsCmd(jobExecutor);
    CommandExecutor commandExecutor =
        processEngineImpl.getProcessEngineConfiguration().getCommandExecutorTxRequired();
    commandExecutor.execute(acquireJobsCmd);

    // Try to delete the job. This should fail.
    try {
      managementService.deleteJob(timerJob.getId());
      fail();
    } catch (ProcessEngineException e) {
      // Exception is expected
    }

    // Clean up
    managementService.executeJob(timerJob.getId());
  }
  @Deployment
  public void testTimerOnConcurrentSubprocess() {
    String procId =
        runtimeService.startProcessInstanceByKey("testTimerOnConcurrentSubprocess").getId();
    assertEquals(4, taskService.createTaskQuery().count());

    Job timer = managementService.createJobQuery().singleResult();
    managementService.executeJob(timer.getId());
    assertEquals(5, taskService.createTaskQuery().count());

    // Complete 4 tasks that will trigger the join
    Task task = taskService.createTaskQuery().taskDefinitionKey("sub1task1").singleResult();
    taskService.complete(task.getId());
    task = taskService.createTaskQuery().taskDefinitionKey("sub1task2").singleResult();
    taskService.complete(task.getId());
    task = taskService.createTaskQuery().taskDefinitionKey("sub2task1").singleResult();
    taskService.complete(task.getId());
    task = taskService.createTaskQuery().taskDefinitionKey("sub2task2").singleResult();
    taskService.complete(task.getId());
    assertEquals(1, taskService.createTaskQuery().count());

    // Finally, complete the task that was created due to the timer
    task = taskService.createTaskQuery().taskDefinitionKey("timerFiredTask").singleResult();
    taskService.complete(task.getId());

    assertProcessEnded(procId);
  }
  @Deployment(
      resources = {
        "org/camunda/bpm/engine/test/api/mgmt/ManagementServiceTest.testGetJobExceptionStacktrace.bpmn20.xml"
      })
  public void testSetJobRetriesNullCreatesIncident() {

    // initially there is no incident
    assertEquals(0, runtimeService.createIncidentQuery().count());

    ProcessInstance processInstance =
        runtimeService.startProcessInstanceByKey("exceptionInJobExecution");

    // The execution is waiting in the first usertask. This contains a boundary
    // timer event.
    Job timerJob =
        managementService
            .createJobQuery()
            .processInstanceId(processInstance.getId())
            .singleResult();

    assertNotNull("No job found for process instance", timerJob);
    assertEquals(JobEntity.DEFAULT_RETRIES, timerJob.getRetries());

    managementService.setJobRetries(timerJob.getId(), 0);

    timerJob =
        managementService
            .createJobQuery()
            .processInstanceId(processInstance.getId())
            .singleResult();
    assertEquals(0, timerJob.getRetries());

    assertEquals(1, runtimeService.createIncidentQuery().count());
  }
  @Deployment(resources = NESTED_PARALLEL_ASYNC_BEFORE_SCOPE_TASK_PROCESS)
  public void testCancelNestedConcurrentTransitionInstanceWithConcurrentScopeTask() {
    // given a process instance where the job for innerTask2 is already executed
    ProcessInstance processInstance =
        runtimeService.startProcessInstanceByKey("nestedConcurrentTasksProcess");
    String processInstanceId = processInstance.getId();

    Job innerTask2Job = managementService.createJobQuery().activityId("innerTask2").singleResult();
    assertNotNull(innerTask2Job);
    managementService.executeJob(innerTask2Job.getId());

    // when the transition instance to innerTask1 is cancelled
    ActivityInstance tree = runtimeService.getActivityInstance(processInstanceId);

    runtimeService
        .createProcessInstanceModification(processInstance.getId())
        .cancelTransitionInstance(
            getChildTransitionInstanceForTargetActivity(tree, "innerTask1").getId())
        .execute();

    // then the activity instance and execution tree should match
    ActivityInstance updatedTree = runtimeService.getActivityInstance(processInstanceId);
    assertThat(updatedTree)
        .hasStructure(
            describeActivityInstanceTree(processInstance.getProcessDefinitionId())
                .activity("outerTask")
                .beginScope("subProcess")
                .activity("innerTask2")
                .done());

    ExecutionTree executionTree =
        ExecutionTree.forExecution(processInstance.getId(), processEngine);

    assertThat(executionTree)
        .matches(
            describeExecutionTree(null)
                .scope()
                .child("outerTask")
                .concurrent()
                .noScope()
                .up()
                .child(null)
                .concurrent()
                .noScope()
                .child(null)
                .scope()
                .child("innerTask2")
                .scope()
                .done());

    // and there should be no job for innerTask1 anymore
    assertEquals(0, managementService.createJobQuery().activityId("innerTask1").count());

    // and completing the process should succeed
    completeTasksInOrder("innerTask2", "outerTask");

    assertProcessEnded(processInstanceId);
  }
  @Deployment
  public void testLongProcessDefinitionKey() {
    String key = "myrealrealrealrealrealrealrealrealrealrealreallongprocessdefinitionkeyawesome";
    String processInstanceId = runtimeService.startProcessInstanceByKey(key).getId();

    Job job =
        managementService.createJobQuery().processInstanceId(processInstanceId).singleResult();

    assertEquals(key, job.getProcessDefinitionKey());
  }
 /**
  * Helper method to easily execute a job.
  *
  * @param job Job to be executed.
  */
 public static void execute(Job job) {
   if (job == null)
     throw new IllegalArgumentException(
         format("Illegal call of execute(job = '%s') - must not be null!", job));
   Job current = jobQuery().jobId(job.getId()).singleResult();
   if (current == null)
     throw new IllegalStateException(
         format(
             "Illegal state when calling execute(job = '%s') - job does not exist anymore!", job));
   managementService().executeJob(job.getId());
 }
  @Deployment
  public void testMultipleOutgoingSequenceFlowsOnSubprocess() {
    ProcessInstance pi = runtimeService.startProcessInstanceByKey("nonInterruptingTimer");

    Job job = managementService.createJobQuery().singleResult();
    assertNotNull(job);

    managementService.executeJob(job.getId());

    Task task = taskService.createTaskQuery().taskDefinitionKey("innerTask1").singleResult();
    assertNotNull(task);
    taskService.complete(task.getId());

    task = taskService.createTaskQuery().taskDefinitionKey("innerTask2").singleResult();
    assertNotNull(task);
    taskService.complete(task.getId());

    task = taskService.createTaskQuery().taskDefinitionKey("timerFiredTask1").singleResult();
    assertNotNull(task);
    taskService.complete(task.getId());

    task = taskService.createTaskQuery().taskDefinitionKey("timerFiredTask2").singleResult();
    assertNotNull(task);
    taskService.complete(task.getId());

    assertProcessEnded(pi.getId());

    // Case 2: fire outer tasks first

    pi = runtimeService.startProcessInstanceByKey("nonInterruptingTimer");

    job = managementService.createJobQuery().singleResult();
    assertNotNull(job);

    managementService.executeJob(job.getId());

    task = taskService.createTaskQuery().taskDefinitionKey("timerFiredTask1").singleResult();
    assertNotNull(task);
    taskService.complete(task.getId());

    task = taskService.createTaskQuery().taskDefinitionKey("timerFiredTask2").singleResult();
    assertNotNull(task);
    taskService.complete(task.getId());

    task = taskService.createTaskQuery().taskDefinitionKey("innerTask1").singleResult();
    assertNotNull(task);
    taskService.complete(task.getId());

    task = taskService.createTaskQuery().taskDefinitionKey("innerTask2").singleResult();
    assertNotNull(task);
    taskService.complete(task.getId());

    assertProcessEnded(pi.getId());
  }
  public void testDeploymentWithDelayedProcessDefinitionAndJobDefinitionActivation() {

    Date startTime = new Date();
    ClockUtil.setCurrentTime(startTime);
    Date inThreeDays = new Date(startTime.getTime() + (3 * 24 * 60 * 60 * 1000));

    // Deploy process, but activate after three days
    org.camunda.bpm.engine.repository.Deployment deployment =
        repositoryService
            .createDeployment()
            .addClasspathResource("org/camunda/bpm/engine/test/api/oneAsyncTask.bpmn")
            .activateProcessDefinitionsOn(inThreeDays)
            .deploy();

    assertEquals(1, repositoryService.createDeploymentQuery().count());

    assertEquals(1, repositoryService.createProcessDefinitionQuery().count());
    assertEquals(1, repositoryService.createProcessDefinitionQuery().suspended().count());
    assertEquals(0, repositoryService.createProcessDefinitionQuery().active().count());

    assertEquals(1, managementService.createJobDefinitionQuery().count());
    assertEquals(1, managementService.createJobDefinitionQuery().suspended().count());
    assertEquals(0, managementService.createJobDefinitionQuery().active().count());

    // Shouldn't be able to start a process instance
    try {
      runtimeService.startProcessInstanceByKey("oneTaskProcess");
      fail();
    } catch (ProcessEngineException e) {
      assertTextPresentIgnoreCase("suspended", e.getMessage());
    }

    Job job = managementService.createJobQuery().singleResult();
    managementService.executeJob(job.getId());

    assertEquals(1, repositoryService.createDeploymentQuery().count());

    assertEquals(1, repositoryService.createProcessDefinitionQuery().count());
    assertEquals(0, repositoryService.createProcessDefinitionQuery().suspended().count());
    assertEquals(1, repositoryService.createProcessDefinitionQuery().active().count());

    assertEquals(1, managementService.createJobDefinitionQuery().count());
    assertEquals(0, managementService.createJobDefinitionQuery().suspended().count());
    assertEquals(1, managementService.createJobDefinitionQuery().active().count());

    // Should be able to start process instance
    runtimeService.startProcessInstanceByKey("oneTaskProcess");
    assertEquals(1, runtimeService.createProcessInstanceQuery().count());

    // Cleanup
    repositoryService.deleteDeployment(deployment.getId(), true);
  }
 public void executeJob(Job job) {
   assertNotNull("Job to execute does not exist", job);
   try {
     engineRule.getManagementService().executeJob(job.getId());
   } catch (Exception e) {
     // ignore
   }
 }
  @Deployment(resources = {"org/camunda/bpm/engine/test/api/mgmt/SuspensionTest.testBase.bpmn"})
  public void testActivationByJobDefinitionId_shouldActivateJob() {
    // given

    // a running process instance with a failed job
    Map<String, Object> params = new HashMap<String, Object>();
    params.put("fail", Boolean.TRUE);
    runtimeService.startProcessInstanceByKey("suspensionProcess", params);

    // suspended job definitions and corresponding jobs
    managementService.suspendJobDefinitionByProcessDefinitionKey("suspensionProcess", true);

    // the job definition
    JobDefinition jobDefinition = managementService.createJobDefinitionQuery().singleResult();

    // the failed job
    JobQuery jobQuery = managementService.createJobQuery();
    Job job = jobQuery.singleResult();
    assertTrue(job.isSuspended());

    // when
    // the job will be activated
    managementService.activateJobByJobDefinitionId(jobDefinition.getId());

    // then
    // the job should be activated
    assertEquals(0, jobQuery.suspended().count());
    assertEquals(1, jobQuery.active().count());

    Job activeJob = jobQuery.active().singleResult();

    assertEquals(job.getId(), activeJob.getId());
    assertEquals(jobDefinition.getId(), activeJob.getJobDefinitionId());
    assertFalse(activeJob.isSuspended());
  }
  @Deployment
  public void testAsyncServiceSubProcessTimer() {
    INVOCATION = false;
    // start process
    runtimeService.startProcessInstanceByKey("asyncService");
    // now there should be two jobs in the database:
    assertEquals(2, managementService.createJobQuery().count());
    // the service was not invoked:
    assertFalse(INVOCATION);

    Job job = managementService.createJobQuery().messages().singleResult();
    managementService.executeJob(job.getId());

    // the service was invoked
    assertTrue(INVOCATION);
    // both the timer and the message are cancelled
    assertEquals(0, managementService.createJobQuery().count());
  }
  @Deployment(resources = "org/camunda/bpm/engine/test/api/mgmt/asyncTaskProcess.bpmn20.xml")
  public void testSetJobPriority() {
    // given
    runtimeService
        .createProcessInstanceByKey("asyncTaskProcess")
        .startBeforeActivity("task")
        .execute();

    Job job = managementService.createJobQuery().singleResult();

    // when
    managementService.setJobPriority(job.getId(), 42);

    // then
    job = managementService.createJobQuery().singleResult();

    assertEquals(42, job.getPriority());
  }
  @Deployment(resources = {"org/camunda/bpm/engine/test/api/mgmt/timerOnTask.bpmn20.xml"})
  public void testDeleteJobDeletion() {
    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("timerOnTask");
    Job timerJob =
        managementService
            .createJobQuery()
            .processInstanceId(processInstance.getId())
            .singleResult();

    assertNotNull("Task timer should be there", timerJob);
    managementService.deleteJob(timerJob.getId());

    timerJob =
        managementService
            .createJobQuery()
            .processInstanceId(processInstance.getId())
            .singleResult();
    assertNull("There should be no job now. It was deleted", timerJob);
  }
  @Deployment(resources = "org/camunda/bpm/engine/test/api/mgmt/asyncTaskProcess.bpmn20.xml")
  public void testSetJobPriorityToExtremeValues() {
    runtimeService
        .createProcessInstanceByKey("asyncTaskProcess")
        .startBeforeActivity("task")
        .execute();

    Job job = managementService.createJobQuery().singleResult();

    // it is possible to set the max integer value
    managementService.setJobPriority(job.getId(), Long.MAX_VALUE);
    job = managementService.createJobQuery().singleResult();
    assertEquals(Long.MAX_VALUE, job.getPriority());

    // it is possible to set the min integer value
    managementService.setJobPriority(job.getId(), Long.MIN_VALUE + 1); // +1 for informix
    job = managementService.createJobQuery().singleResult();
    assertEquals(Long.MIN_VALUE + 1, job.getPriority());
  }
 public List<HistoricJobLog> getHistoricMonitorJobLog(Batch batch, Job monitorJob) {
   return engineRule
       .getHistoryService()
       .createHistoricJobLogQuery()
       .jobDefinitionId(batch.getMonitorJobDefinitionId())
       .jobId(monitorJob.getId())
       .orderPartiallyByOccurrence()
       .asc()
       .list();
 }
  @Deployment
  public void testMultipleOutgoingSequenceFlowsOnSubprocessMi() {
    ProcessInstance pi = runtimeService.startProcessInstanceByKey("nonInterruptingTimer");

    Job job = managementService.createJobQuery().singleResult();
    assertNotNull(job);

    managementService.executeJob(job.getId());

    TaskQuery taskQuery = taskService.createTaskQuery();
    assertEquals(10, taskQuery.count());

    List<Task> tasks = taskQuery.list();

    for (Task task : tasks) {
      taskService.complete(task.getId());
    }

    assertProcessEnded(pi.getId());
  }
  @Deployment(resources = {"org/camunda/bpm/engine/test/jobexecutor/simpleAsyncProcess.bpmn20.xml"})
  public void testSuspendJobDuringExecution() {

    runtimeService.startProcessInstanceByKey("simpleAsyncProcess");
    Job job = managementService.createJobQuery().singleResult();

    // given a waiting execution and a waiting suspension
    JobExecutionThread executionthread = new JobExecutionThread(job.getId());
    executionthread.startAndWaitUntilControlIsReturned();

    JobSuspensionThread jobSuspensionThread = new JobSuspensionThread("simpleAsyncProcess");
    jobSuspensionThread.startAndWaitUntilControlIsReturned();

    // first complete suspension:
    jobSuspensionThread.proceedAndWaitTillDone();
    executionthread.proceedAndWaitTillDone();

    // then the execution will fail with optimistic locking
    assertNull(jobSuspensionThread.exception);
    assertNotNull(executionthread.exception);

    // --------------------------------------------

    // given a waiting execution and a waiting suspension
    executionthread = new JobExecutionThread(job.getId());
    executionthread.startAndWaitUntilControlIsReturned();

    jobSuspensionThread = new JobSuspensionThread("simpleAsyncProcess");
    jobSuspensionThread.startAndWaitUntilControlIsReturned();

    // first complete execution:
    executionthread.proceedAndWaitTillDone();
    jobSuspensionThread.proceedAndWaitTillDone();

    // then there are no optimistic locking exceptions
    assertNull(jobSuspensionThread.exception);
    assertNull(executionthread.exception);

    // clean up log
    TestHelper.clearOpLog(processEngineConfiguration);
  }
  @Deployment
  public void testTimerOnConcurrentTasks() {
    String procId =
        runtimeService.startProcessInstanceByKey("nonInterruptingOnConcurrentTasks").getId();
    assertEquals(2, taskService.createTaskQuery().count());

    Job timer = managementService.createJobQuery().singleResult();
    managementService.executeJob(timer.getId());
    assertEquals(3, taskService.createTaskQuery().count());

    // Complete task that was reached by non interrupting timer
    Task task = taskService.createTaskQuery().taskDefinitionKey("timerFiredTask").singleResult();
    taskService.complete(task.getId());
    assertEquals(2, taskService.createTaskQuery().count());

    // Complete other tasks
    for (Task t : taskService.createTaskQuery().list()) {
      taskService.complete(t.getId());
    }
    assertProcessEnded(procId);
  }
  @Deployment
  public void testGetJobExceptionStacktrace() {
    ProcessInstance processInstance =
        runtimeService.startProcessInstanceByKey("exceptionInJobExecution");

    // The execution is waiting in the first usertask. This contains a boundry
    // timer event which we will execute manual for testing purposes.
    Job timerJob =
        managementService
            .createJobQuery()
            .processInstanceId(processInstance.getId())
            .singleResult();

    assertNotNull("No job found for process instance", timerJob);

    try {
      managementService.executeJob(timerJob.getId());
      fail("RuntimeException from within the script task expected");
    } catch (RuntimeException re) {
      assertTextPresent("This is an exception thrown from scriptTask", re.getMessage());
    }

    // Fetch the task to see that the exception that occurred is persisted
    timerJob =
        managementService
            .createJobQuery()
            .processInstanceId(processInstance.getId())
            .singleResult();

    Assert.assertNotNull(timerJob);
    Assert.assertNotNull(timerJob.getExceptionMessage());
    assertTextPresent(
        "This is an exception thrown from scriptTask", timerJob.getExceptionMessage());

    // Get the full stacktrace using the managementService
    String exceptionStack = managementService.getJobExceptionStacktrace(timerJob.getId());
    Assert.assertNotNull(exceptionStack);
    assertTextPresent("This is an exception thrown from scriptTask", exceptionStack);
  }
  @Deployment(resources = ASYNC_BEFORE_ONE_TASK_PROCESS)
  public void testCancelAndStartAsyncBeforeTransitionInstance() {
    // given
    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("oneTaskProcess");
    String processInstanceId = processInstance.getId();

    ActivityInstance tree = runtimeService.getActivityInstance(processInstance.getId());
    Job asyncJob = managementService.createJobQuery().singleResult();

    // when cancelling the only transition instance in the process and immediately starting it again
    runtimeService
        .createProcessInstanceModification(processInstanceId)
        .cancelTransitionInstance(
            getChildTransitionInstanceForTargetActivity(tree, "theTask").getId())
        .startBeforeActivity("theTask")
        .execute();

    // then the activity instance tree should be as before
    ActivityInstance updatedTree = runtimeService.getActivityInstance(processInstance.getId());
    assertThat(updatedTree)
        .hasStructure(
            describeActivityInstanceTree(processInstance.getProcessDefinitionId())
                .transition("theTask")
                .done());

    // and the async job should be a new one
    Job newAsyncJob = managementService.createJobQuery().singleResult();
    assertFalse(asyncJob.getId().equals(newAsyncJob.getId()));

    ExecutionTree executionTree =
        ExecutionTree.forExecution(processInstance.getId(), processEngine);

    assertThat(executionTree).matches(describeExecutionTree("theTask").scope().done());

    // and the process can be completed successfully
    executeAvailableJobs();
    completeTasksInOrder("theTask");
    assertProcessEnded(processInstance.getId());
  }
  @Deployment(
      resources = {
        "org/camunda/bpm/engine/test/api/mgmt/ManagementServiceTest.testGetJobExceptionStacktrace.bpmn20.xml"
      })
  public void testSetJobRetriesByJobDefinitionId() {
    ProcessInstance processInstance =
        runtimeService.startProcessInstanceByKey("exceptionInJobExecution");
    executeAvailableJobs();

    JobQuery query = managementService.createJobQuery().processInstanceId(processInstance.getId());

    JobDefinition jobDefinition = managementService.createJobDefinitionQuery().singleResult();

    Job timerJob = query.singleResult();

    assertNotNull("No job found for process instance", timerJob);
    assertEquals(0, timerJob.getRetries());

    managementService.setJobRetriesByJobDefinitionId(jobDefinition.getId(), 5);

    timerJob = query.singleResult();
    assertEquals(5, timerJob.getRetries());
  }
  @Deployment
  public void testTimerOnConcurrentMiTasks() {

    // After process start, there should be 1 timer created
    ProcessInstance pi = runtimeService.startProcessInstanceByKey("timerOnConcurrentMiTasks");
    List<Task> taskList = taskService.createTaskQuery().orderByTaskName().desc().list();
    assertEquals(6, taskList.size());
    Task secondTask = taskList.remove(0);
    assertEquals("Second Task", secondTask.getName());
    for (Task task : taskList) {
      assertEquals("First Task", task.getName());
    }

    Job job = managementService.createJobQuery().processInstanceId(pi.getId()).singleResult();
    assertNotNull(job);

    // execute the timer
    managementService.executeJob(job.getId());

    // now there are 7 tasks
    taskList = taskService.createTaskQuery().orderByTaskName().asc().list();
    assertEquals(7, taskList.size());

    // first task is the escalation task
    Task escalationTask = taskList.remove(0);
    assertEquals("Escalation Task 1", escalationTask.getName());
    // complete it
    taskService.complete(escalationTask.getId());

    // now complete the remaining tasks
    for (Task task : taskList) {
      taskService.complete(task.getId());
    }

    // process instance is ended
    assertProcessEnded(pi.getId());
  }