Package org.camunda.bpm.engine.test.bpmn.subprocess.transaction

Source Code of org.camunda.bpm.engine.test.bpmn.subprocess.transaction.TransactionSubProcessTest

/* 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.camunda.bpm.engine.test.bpmn.subprocess.transaction;

import java.util.List;

import org.camunda.bpm.engine.ProcessEngineConfiguration;
import org.camunda.bpm.engine.impl.persistence.entity.EventSubscriptionEntity;
import org.camunda.bpm.engine.impl.test.PluggableProcessEngineTestCase;
import org.camunda.bpm.engine.runtime.ActivityInstance;
import org.camunda.bpm.engine.runtime.EventSubscription;
import org.camunda.bpm.engine.runtime.Execution;
import org.camunda.bpm.engine.runtime.ProcessInstance;
import org.camunda.bpm.engine.task.Task;
import org.camunda.bpm.engine.test.Deployment;


/**
* @author Daniel Meyer
*/
public class TransactionSubProcessTest extends PluggableProcessEngineTestCase {

 
  @Deployment(resources={"org/camunda/bpm/engine/test/bpmn/subprocess/transaction/TransactionSubProcessTest.testSimpleCase.bpmn20.xml"})
  public void testSimpleCaseTxSuccessful() {
   
    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("transactionProcess");
   
    // after the process is started, we have compensate event subscriptions:
    assertEquals(5, runtimeService.createEventSubscriptionQuery().eventType("compensate").activityId("undoBookHotel").count());
    assertEquals(1, runtimeService.createEventSubscriptionQuery().eventType("compensate").activityId("undoBookFlight").count());
   
    // the task is present:
    Task task = taskService.createTaskQuery().singleResult();
    assertNotNull(task);
   
    // making the tx succeed:
    taskService.setVariable(task.getId(), "confirmed", true);   
    taskService.complete(task.getId());
   
    // now the process instance execution is sitting in the 'afterSuccess' task
    // -> has left the transaction using the "normal" sequence flow
    List<String> activeActivityIds = runtimeService.getActiveActivityIds(processInstance.getId());
    assertTrue(activeActivityIds.contains("afterSuccess"));
   
    // there is a compensate event subscription for the transaction under the process instance
    EventSubscriptionEntity eventSubscriptionEntity = (EventSubscriptionEntity) runtimeService.createEventSubscriptionQuery()
        .eventType("compensate").activityId("tx").executionId(processInstance.getId()).singleResult();
   
    // there is an event-scope execution associated with the event-subscription:
    assertNotNull(eventSubscriptionEntity.getConfiguration());
    Execution eventScopeExecution = runtimeService.createExecutionQuery().executionId(eventSubscriptionEntity.getConfiguration()).singleResult();
    assertNotNull(eventScopeExecution);
   
    // we still have compensate event subscriptions for the compensation handlers, only now they are part of the event scope
    assertEquals(5, runtimeService.createEventSubscriptionQuery().eventType("compensate").activityId("undoBookHotel").executionId(eventScopeExecution.getId()).count());
    assertEquals(1, runtimeService.createEventSubscriptionQuery().eventType("compensate").activityId("undoBookFlight").executionId(eventScopeExecution.getId()).count());
    assertEquals(1, runtimeService.createEventSubscriptionQuery().eventType("compensate").activityId("undoChargeCard").executionId(eventScopeExecution.getId()).count());
   
    // assert that the compensation handlers have not been invoked:
    assertNull(runtimeService.getVariable(processInstance.getId(), "undoBookHotel"));
    assertNull(runtimeService.getVariable(processInstance.getId(), "undoBookFlight"));
    assertNull(runtimeService.getVariable(processInstance.getId(), "undoChargeCard"));
          
    // end the process instance
    runtimeService.signal(processInstance.getId());   
    assertProcessEnded(processInstance.getId());   
    assertEquals(0, runtimeService.createExecutionQuery().count());
   
  }
 
  @Deployment(resources={"org/camunda/bpm/engine/test/bpmn/subprocess/transaction/TransactionSubProcessTest.testWaitstateCompensationHandler.bpmn20.xml"})
  public void testWaitstateCompensationHandler() {

    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("transactionProcess");
   
    // after the process is started, we have compensate event subscriptions:
    assertEquals(5, runtimeService.createEventSubscriptionQuery().eventType("compensate").activityId("undoBookHotel").count());
    assertEquals(1, runtimeService.createEventSubscriptionQuery().eventType("compensate").activityId("undoBookFlight").count());
   
    // the task is present:
    Task task = taskService.createTaskQuery().singleResult();
    assertNotNull(task);
   
    // making the tx fail:
    taskService.setVariable(task.getId(), "confirmed", false);   
    taskService.complete(task.getId());
   
    // now there are two user task instances (the compensation handlers):
   
    List<Task> undoBookHotel = taskService.createTaskQuery().taskDefinitionKey("undoBookHotel").list();
    List<Task> undoBookFlight = taskService.createTaskQuery().taskDefinitionKey("undoBookFlight").list();
   
    assertEquals(5,undoBookHotel.size());
    assertEquals(1,undoBookFlight.size());
   
    ActivityInstance rootActivityInstance = runtimeService.getActivityInstance(processInstance.getId());
    List<ActivityInstance> undoBookHotelInstances = getInstancesForActivitiyId(rootActivityInstance, "undoBookHotel");
    List<ActivityInstance> undoBookFlightInstances = getInstancesForActivitiyId(rootActivityInstance, "undoBookFlight");
    assertEquals(5, undoBookHotelInstances.size());
    assertEquals(1, undoBookFlightInstances.size());
   
    ActivityInstance txActivityInstance = rootActivityInstance.getChildActivityInstances()[0];
    assertEquals("tx", txActivityInstance.getActivityId());
    assertEquals(7, txActivityInstance.getChildActivityInstances().length);
   
    for (Task t : undoBookHotel) {
      taskService.complete(t.getId());     
    }
    taskService.complete(undoBookFlight.get(0).getId());
       
    // now the process instance execution is sitting in the 'afterCancellation' task
    // -> has left the transaction using the cancel boundary event
    List<String> activeActivityIds = runtimeService.getActiveActivityIds(processInstance.getId());
    assertTrue(activeActivityIds.contains("afterCancellation"));
   
    // we have no more compensate event subscriptions
    assertEquals(0, runtimeService.createEventSubscriptionQuery().eventType("compensate").count());
      
    // end the process instance
    runtimeService.signal(processInstance.getId());   
    assertProcessEnded(processInstance.getId());
    assertEquals(0, runtimeService.createExecutionQuery().count());   
  }
 
  @Deployment(resources={"org/camunda/bpm/engine/test/bpmn/subprocess/transaction/TransactionSubProcessTest.testSimpleCase.bpmn20.xml"})
  public void testSimpleCaseTxCancelled() {
   
    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("transactionProcess");
   
    // after the process is started, we have compensate event subscriptions:
    assertEquals(5, runtimeService.createEventSubscriptionQuery().eventType("compensate").activityId("undoBookHotel").count());
    assertEquals(1,runtimeService.createEventSubscriptionQuery().eventType("compensate").activityId("undoBookFlight").count());
   
    // the task is present:
    Task task = taskService.createTaskQuery().singleResult();
    assertNotNull(task);
   
    // making the tx fail:
    taskService.setVariable(task.getId(), "confirmed", false);   
    taskService.complete(task.getId());
   
    // now the process instance execution is sitting in the 'afterCancellation' task
    // -> has left the transaction using the cancel boundary event
    List<String> activeActivityIds = runtimeService.getActiveActivityIds(processInstance.getId());
    assertTrue(activeActivityIds.contains("afterCancellation"));
   
    // we have no more compensate event subscriptions
    assertEquals(0,runtimeService.createEventSubscriptionQuery().eventType("compensate").count());
   
    // assert that the compensation handlers have been invoked:
    assertEquals(5, runtimeService.getVariable(processInstance.getId(), "undoBookHotel"));
    assertEquals(1, runtimeService.getVariable(processInstance.getId(), "undoBookFlight"));
    assertEquals(1, runtimeService.getVariable(processInstance.getId(), "undoChargeCard"));
   
    // if we have history, we check that the invocation of the compensation handlers is recorded in history.
    if(!processEngineConfiguration.getHistory().equals(ProcessEngineConfiguration.HISTORY_NONE)) {
      assertEquals(1, historyService.createHistoricActivityInstanceQuery()
              .activityId("undoBookFlight")
              .count());
     
      assertEquals(5, historyService.createHistoricActivityInstanceQuery()
              .activityId("undoBookHotel")
              .count());
     
      assertEquals(1, historyService.createHistoricActivityInstanceQuery()
              .activityId("undoChargeCard")
              .count());
    }
  
    // end the process instance
    runtimeService.signal(processInstance.getId());   
    assertProcessEnded(processInstance.getId());
    assertEquals(0, runtimeService.createExecutionQuery().count());   
  }
 

  @Deployment
  public void testCancelEndConcurrent() {
   
    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("transactionProcess");
   
    // after the process is started, we have compensate event subscriptions:
    assertEquals(5,runtimeService.createEventSubscriptionQuery().eventType("compensate").activityId("undoBookHotel").count());
    assertEquals(1,runtimeService.createEventSubscriptionQuery().eventType("compensate").activityId("undoBookFlight").count());
   
    // the task is present:
    Task task = taskService.createTaskQuery().singleResult();
    assertNotNull(task);
   
    // making the tx fail:
    taskService.setVariable(task.getId(), "confirmed", false);   
    taskService.complete(task.getId());
   
    // now the process instance execution is sitting in the 'afterCancellation' task
    // -> has left the transaction using the cancel boundary event
    List<String> activeActivityIds = runtimeService.getActiveActivityIds(processInstance.getId());
    assertTrue(activeActivityIds.contains("afterCancellation"));
   
    // we have no more compensate event subscriptions
    assertEquals(0,runtimeService.createEventSubscriptionQuery().eventType("compensate").count());
   
    // assert that the compensation handlers have been invoked:
    assertEquals(5, runtimeService.getVariable(processInstance.getId(), "undoBookHotel"));
    assertEquals(1, runtimeService.getVariable(processInstance.getId(), "undoBookFlight"));
   
    // if we have history, we check that the invocation of the compensation handlers is recorded in history.
    if(!processEngineConfiguration.getHistory().equals(ProcessEngineConfiguration.HISTORY_NONE)) {
      assertEquals(1, historyService.createHistoricActivityInstanceQuery()
              .activityId("undoBookFlight")
              .count());
     
      assertEquals(5, historyService.createHistoricActivityInstanceQuery()
              .activityId("undoBookHotel")
              .count());
    }
  
    // end the process instance
    runtimeService.signal(processInstance.getId());   
    assertProcessEnded(processInstance.getId());
    assertEquals(0, runtimeService.createExecutionQuery().count());   
  }
 
  @Deployment
  public void testNestedCancelInner() {

    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("transactionProcess");
   
    // after the process is started, we have compensate event subscriptions:
    assertEquals(0,runtimeService.createEventSubscriptionQuery().eventType("compensate").activityId("undoBookFlight").count());
    assertEquals(5,runtimeService.createEventSubscriptionQuery().eventType("compensate").activityId("innerTxundoBookHotel").count());
    assertEquals(1,runtimeService.createEventSubscriptionQuery().eventType("compensate").activityId("innerTxundoBookFlight").count());
   
    // the tasks are present:
    Task taskInner = taskService.createTaskQuery().taskDefinitionKey("innerTxaskCustomer").singleResult();
    Task taskOuter = taskService.createTaskQuery().taskDefinitionKey("bookFlight").singleResult();
    assertNotNull(taskInner);
    assertNotNull(taskOuter);
   
    // making the tx fail:
    taskService.setVariable(taskInner.getId(), "confirmed", false);   
    taskService.complete(taskInner.getId());
       
    // now the process instance execution is sitting in the 'afterInnerCancellation' task
    // -> has left the transaction using the cancel boundary event
    List<String> activeActivityIds = runtimeService.getActiveActivityIds(processInstance.getId());
    assertTrue(activeActivityIds.contains("afterInnerCancellation"));
   
    // we have no more compensate event subscriptions for the inner tx
    assertEquals(0,runtimeService.createEventSubscriptionQuery().eventType("compensate").activityId("innerTxundoBookHotel").count());
    assertEquals(0,runtimeService.createEventSubscriptionQuery().eventType("compensate").activityId("innerTxundoBookFlight").count());
  
    // we do not have a subscription or the outer tx yet
    assertEquals(0,runtimeService.createEventSubscriptionQuery().eventType("compensate").activityId("undoBookFlight").count());

    // assert that the compensation handlers have been invoked:
    assertEquals(5, runtimeService.getVariable(processInstance.getId(), "innerTxundoBookHotel"));
    assertEquals(1, runtimeService.getVariable(processInstance.getId(), "innerTxundoBookFlight"));
   
    // if we have history, we check that the invocation of the compensation handlers is recorded in history.
    if(!processEngineConfiguration.getHistory().equals(ProcessEngineConfiguration.HISTORY_NONE)) {
      assertEquals(5, historyService.createHistoricActivityInstanceQuery()
              .activityId("innerTxundoBookHotel")
              .count());
     
      assertEquals(1, historyService.createHistoricActivityInstanceQuery()
              .activityId("innerTxundoBookFlight")
              .count());
    }

    // complete the task in the outer tx
    taskService.complete(taskOuter.getId());
   
    // end the process instance (signal the execution still sitting in afterInnerCancellation)
    runtimeService.signal(runtimeService.createExecutionQuery().activityId("afterInnerCancellation").singleResult().getId());  
   
    assertProcessEnded(processInstance.getId());
    assertEquals(0, runtimeService.createExecutionQuery().count());   
  }
 
  @Deployment
  public void testNestedCancelOuter() {

    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("transactionProcess");
   
    // after the process is started, we have compensate event subscriptions:
    assertEquals(0,runtimeService.createEventSubscriptionQuery().eventType("compensate").activityId("undoBookFlight").count());
    assertEquals(5,runtimeService.createEventSubscriptionQuery().eventType("compensate").activityId("innerTxundoBookHotel").count());
    assertEquals(1,runtimeService.createEventSubscriptionQuery().eventType("compensate").activityId("innerTxundoBookFlight").count());
   
    // the tasks are present:
    Task taskInner = taskService.createTaskQuery().taskDefinitionKey("innerTxaskCustomer").singleResult();
    Task taskOuter = taskService.createTaskQuery().taskDefinitionKey("bookFlight").singleResult();
    assertNotNull(taskInner);
    assertNotNull(taskOuter);
   
    // making the outer tx fail (invokes cancel end event)
    taskService.complete(taskOuter.getId());
       
    // now the process instance is sitting in 'afterOuterCancellation'
    List<String> activeActivityIds = runtimeService.getActiveActivityIds(processInstance.getId());
    assertTrue(activeActivityIds.contains("afterOuterCancellation"));
   
    // we have no more compensate event subscriptions
    assertEquals(0,runtimeService.createEventSubscriptionQuery().eventType("compensate").activityId("innerTxundoBookHotel").count());
    assertEquals(0,runtimeService.createEventSubscriptionQuery().eventType("compensate").activityId("innerTxundoBookFlight").count());
    assertEquals(0,runtimeService.createEventSubscriptionQuery().eventType("compensate").activityId("undoBookFlight").count());

    // the compensation handlers of the inner tx have not been invoked
    assertNull(runtimeService.getVariable(processInstance.getId(), "innerTxundoBookHotel"));
    assertNull(runtimeService.getVariable(processInstance.getId(), "innerTxundoBookFlight"));

    // the compensation handler in the outer tx has been invoked
    assertEquals(1, runtimeService.getVariable(processInstance.getId(), "undoBookFlight"));
   
    // end the process instance (signal the execution still sitting in afterOuterCancellation)
    runtimeService.signal(runtimeService.createExecutionQuery().activityId("afterOuterCancellation").singleResult().getId());  
   
    assertProcessEnded(processInstance.getId());
    assertEquals(0, runtimeService.createExecutionQuery().count())
   
  }
 
  /*
   * The cancel end event cancels all instances, compensation is performed for all instances
   *
   * see spec page 470:
   * "If the cancelActivity attribute is set, the Activity the Event is attached to is then
   * cancelled (in case of a multi-instance, all its instances are cancelled);"
   */
  @Deployment
  public void testMultiInstanceTx() {
   
    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("transactionProcess");
   
    // there are now 5 instances of the transaction:
   
    List<EventSubscription> eventSubscriptions = runtimeService.createEventSubscriptionQuery()
      .eventType("compensate")
      .list();
   
    // there are 10 compensation event subscriptions
    assertEquals(10, eventSubscriptions.size());
   
    // the event subscriptions are all under the same execution (the execution of the multi-instance wrapper)
    String executionId = eventSubscriptions.get(0).getExecutionId();
    for (EventSubscription eventSubscription : eventSubscriptions) {
      if(!executionId.equals(eventSubscription.getExecutionId())) {
        fail("subscriptions not under same execution");
      }
    }
   
    Task task = taskService.createTaskQuery().listPage(0, 1).get(0);
   
    // canceling one instance triggers compensation for all other instances:   
    taskService.setVariable(task.getId(), "confirmed", false);   
    taskService.complete(task.getId());
   
    assertEquals(0, runtimeService.createEventSubscriptionQuery().count());
   
    assertEquals(5, runtimeService.getVariable(processInstance.getId(), "undoBookHotel"));
    assertEquals(5, runtimeService.getVariable(processInstance.getId(), "undoBookFlight"));
   
    runtimeService.signal(runtimeService.createExecutionQuery().activityId("afterCancellation").singleResult().getId());  
   
    assertProcessEnded(processInstance.getId());   
  }
 
  @Deployment(resources={"org/camunda/bpm/engine/test/bpmn/subprocess/transaction/TransactionSubProcessTest.testMultiInstanceTx.bpmn20.xml"})
  public void testMultiInstanceTxSuccessful() {
   
    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("transactionProcess");
   
    // there are now 5 instances of the transaction:
   
    List<EventSubscription> eventSubscriptions = runtimeService.createEventSubscriptionQuery()
      .eventType("compensate")
      .list();
   
    // there are 10 compensation event subscriptions
    assertEquals(10, eventSubscriptions.size());
   
    // the event subscriptions are all under the same execution (the execution of the multi-instance wrapper)
    String executionId = eventSubscriptions.get(0).getExecutionId();
    for (EventSubscription eventSubscription : eventSubscriptions) {
      if(!executionId.equals(eventSubscription.getExecutionId())) {
        fail("subscriptions not under same execution");
      }
    }
   
    // first complete the inner user-tasks
    List<Task> tasks = taskService.createTaskQuery().list();
    for (Task task : tasks) {
      taskService.setVariable(task.getId(), "confirmed", true);   
      taskService.complete(task.getId());       
    }
   
    // now complete the inner receive tasks   
    List<Execution> executions = runtimeService.createExecutionQuery().activityId("receive").list();
    for (Execution execution : executions) {
      runtimeService.signal(execution.getId());     
    }
  
    runtimeService.signal(runtimeService.createExecutionQuery().activityId("afterSuccess").singleResult().getId());  
   
    assertEquals(0, runtimeService.createEventSubscriptionQuery().count());
    assertProcessEnded(processInstance.getId());
       
  }
 
  public void testMultipleCancelBoundaryFails() {   
    try {
      repositoryService.createDeployment()
        .addClasspathResource("org/camunda/bpm/engine/test/bpmn/subprocess/transaction/TransactionSubProcessTest.testMultipleCancelBoundaryFails.bpmn20.xml")
        .deploy();
      fail("exception expected");
    } catch (Exception e) {
      if(!e.getMessage().contains("multiple boundary events with cancelEventDefinition not supported on same transaction")) {
        fail("different exception expected");
      }
    }   
  }
 
  public void testCancelBoundaryNoTransactionFails() {   
    try {
      repositoryService.createDeployment()
        .addClasspathResource("org/camunda/bpm/engine/test/bpmn/subprocess/transaction/TransactionSubProcessTest.testCancelBoundaryNoTransactionFails.bpmn20.xml")
        .deploy();
      fail("exception expected");
    } catch (Exception e) {
      if(!e.getMessage().contains("boundary event with cancelEventDefinition only supported on transaction subprocesses")) {
        fail("different exception expected");
      }
    }   
  }
 
  public void testCancelEndNoTransactionFails() {   
    try {
      repositoryService.createDeployment()
        .addClasspathResource("org/camunda/bpm/engine/test/bpmn/subprocess/transaction/TransactionSubProcessTest.testCancelEndNoTransactionFails.bpmn20.xml")
        .deploy();
      fail("exception expected");
    } catch (Exception e) {
      if(!e.getMessage().contains("end event with cancelEventDefinition only supported inside transaction subprocess")) {
        fail("different exception expected");
      }
    }   
  }
 
  @Deployment
  public void testParseWithDI() {
   
    // this test simply makes sure we can parse a transaction subprocess with DI information
    // the actual transaction behavior is tested by other testcases
   
    //// failing case
   
    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("TransactionSubProcessTest");
   
    Task task = taskService.createTaskQuery().singleResult();
    taskService.setVariable(task.getId(), "confirmed", false);
   
    taskService.complete(task.getId());
   
    assertProcessEnded(processInstance.getId());
   
   
    ////// success case
   
    processInstance = runtimeService.startProcessInstanceByKey("TransactionSubProcessTest");
   
    task = taskService.createTaskQuery().singleResult();
    taskService.setVariable(task.getId(), "confirmed", true);
   
    taskService.complete(task.getId());
   
    assertProcessEnded(processInstance.getId());
  }
}
TOP

Related Classes of org.camunda.bpm.engine.test.bpmn.subprocess.transaction.TransactionSubProcessTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.