<commit_before>package org.flowable.engine.test.cfg.executioncount;
import java.util.List;
import java.util.Map;

import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.impl.cfg.CommandExecutorImpl;
import org.flowable.engine.impl.db.DbSqlSessionFactory;
import org.flowable.engine.impl.history.DefaultHistoryManager;
import org.flowable.engine.impl.history.HistoryLevel;
import org.flowable.engine.impl.interceptor.CommandInterceptor;
import org.flowable.engine.impl.test.PluggableFlowableTestCase;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.task.Task;
import org.flowable.engine.test.profiler.FlowableProfiler;
import org.flowable.engine.test.profiler.CommandStats;
import org.flowable.engine.test.profiler.ConsoleLogger;
import org.flowable.engine.test.profiler.ProfileSession;
import org.flowable.engine.test.profiler.ProfilingDbSqlSessionFactory;
import org.flowable.engine.test.profiler.TotalExecutionTimeCommandInterceptor;
import org.junit.Assert;

/**
 * @author <NAME>
 */
public class VerifyDatabaseOperationsTest extends PluggableFlowableTestCase {
  
  protected boolean oldExecutionTreeFetchValue;
  protected boolean oldExecutionRelationshipCountValue;
  protected boolean oldenableProcessDefinitionInfoCacheValue;
  protected CommandInterceptor oldFirstCommandInterceptor;
  protected DbSqlSessionFactory oldDbSqlSessionFactory;
  protected HistoryLevel oldHistoryLevel;
  
  @Override
  protected void setUp() throws Exception {
    super.setUp();

    // Enable flags
    this.oldExecutionTreeFetchValue = processEngineConfiguration.getPerformanceSettings().isEnableEagerExecutionTreeFetching();
    this.oldExecutionRelationshipCountValue = processEngineConfiguration.getPerformanceSettings().isEnableExecutionRelationshipCounts();
    this.oldenableProcessDefinitionInfoCacheValue = processEngineConfiguration.isEnableProcessDefinitionInfoCache();
    oldHistoryLevel = ((DefaultHistoryManager) processEngineConfiguration.getHistoryManager()).getHistoryLevel();

    processEngineConfiguration.getPerformanceSettings().setEnableEagerExecutionTreeFetching(true);
    processEngineConfiguration.getPerformanceSettings().setEnableExecutionRelationshipCounts(true);
    processEngineConfiguration.setEnableProcessDefinitionInfoCache(false);
    ((DefaultHistoryManager) processEngineConfiguration.getHistoryManager()).setHistoryLevel(HistoryLevel.AUDIT);

    // The time interceptor should be first
    CommandExecutorImpl commandExecutor = ((CommandExecutorImpl) processEngineConfiguration.getCommandExecutor());
    this.oldFirstCommandInterceptor = commandExecutor.getFirst();
    
    TotalExecutionTimeCommandInterceptor timeCommandInterceptor = new TotalExecutionTimeCommandInterceptor();
    timeCommandInterceptor.setNext(oldFirstCommandInterceptor);
    commandExecutor.setFirst(timeCommandInterceptor);
    
    // Add dbsqlSession factory that captures CRUD operations
    this.oldDbSqlSessionFactory = processEngineConfiguration.getDbSqlSessionFactory();
    DbSqlSessionFactory newDbSqlSessionFactory = new ProfilingDbSqlSessionFactory();
    newDbSqlSessionFactory.setDatabaseType(oldDbSqlSessionFactory.getDatabaseType());
    newDbSqlSessionFactory.setDatabaseTablePrefix(oldDbSqlSessionFactory.getDatabaseTablePrefix());
    newDbSqlSessionFactory.setTablePrefixIsSchema(oldDbSqlSessionFactory.isTablePrefixIsSchema());
    newDbSqlSessionFactory.setDatabaseCatalog(oldDbSqlSessionFactory.getDatabaseCatalog());
    newDbSqlSessionFactory.setDatabaseSchema(oldDbSqlSessionFactory.getDatabaseSchema());
    newDbSqlSessionFactory.setSqlSessionFactory(oldDbSqlSessionFactory.getSqlSessionFactory());
    newDbSqlSessionFactory.setIdGenerator(oldDbSqlSessionFactory.getIdGenerator());
    newDbSqlSessionFactory.setDbHistoryUsed(oldDbSqlSessionFactory.isDbHistoryUsed());
    processEngineConfiguration.addSessionFactory(newDbSqlSessionFactory);
  }
  
  @Override
  protected void tearDown() throws Exception {
    
    processEngineConfiguration.getPerformanceSettings().setEnableEagerExecutionTreeFetching(oldExecutionTreeFetchValue);
    processEngineConfiguration.getPerformanceSettings().setEnableExecutionRelationshipCounts(oldExecutionRelationshipCountValue);
    processEngineConfiguration.setEnableProcessDefinitionInfoCache(oldenableProcessDefinitionInfoCacheValue);
    ((DefaultHistoryManager) processEngineConfiguration.getHistoryManager()).setHistoryLevel(oldHistoryLevel);
    
    ((CommandExecutorImpl) processEngineConfiguration.getCommandExecutor()).setFirst(oldFirstCommandInterceptor);

    processEngineConfiguration.addSessionFactory(oldDbSqlSessionFactory);
    
    // Validate (cause this tended to be screwed up)
    List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery().list();
    for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
      Assert.assertNotNull(historicActivityInstance.getStartTime());
      Assert.assertNotNull(historicActivityInstance.getEndTime());
    }
    
    FlowableProfiler.getInstance().reset();
    
    for (Deployment deployment : repositoryService.createDeploymentQuery().list()) {
      repositoryService.deleteDeployment(deployment.getId(), true);
    }
    super.tearDown();
  }
  
  public void testStartToEnd() {
    deployStartProcessInstanceAndProfile("process01.bpmn20.xml", "process01");
    
    assertDatabaseSelects("StartProcessInstanceCmd", 
        "selectLatestProcessDefinitionByKey", 1L);
    
    assertDatabaseInserts("StartProcessInstanceCmd", 
        "HistoricActivityInstanceEntityImpl-bulk-with-2", 1L,
        "HistoricProcessInstanceEntityImpl", 1L);
    
    assertNoUpdatesAndDeletes("StartProcessInstanceCmd");
    
    Assert.assertEquals(0, runtimeService.createProcessInstanceQuery().count());
    Assert.assertEquals(1, historyService.createHistoricProcessInstanceQuery().finished().count());
  }
  
  public void testVariablesAndPassthrough() {
    deployStartProcessInstanceAndProfile("process-variables-servicetask01.bpmn20.xml", "process-variables-servicetask01");
    
    assertDatabaseSelects("StartProcessInstanceCmd", 
        "selectLatestProcessDefinitionByKey", 1L);
    assertDatabaseInserts("StartProcessInstanceCmd", 
        "HistoricVariableInstanceEntityImpl-bulk-with-4", 1L,
        "HistoricProcessInstanceEntityImpl", 1L,
        "HistoricActivityInstanceEntityImpl-bulk-with-9", 1L);
    assertNoUpdatesAndDeletes("StartProcessInstanceCmd");
    
    Assert.assertEquals(0, runtimeService.createProcessInstanceQuery().count());
    Assert.assertEquals(1, historyService.createHistoricProcessInstanceQuery().finished().count());
  }

  public void testManyVariablesViaServiceTaskAndPassthroughs() {
    deployStartProcessInstanceAndProfile("process-variables-servicetask02.bpmn20.xml", "process-variables-servicetask02");
    
    assertDatabaseSelects("StartProcessInstanceCmd", 
        "selectLatestProcessDefinitionByKey", 1L);
    assertDatabaseInserts("StartProcessInstanceCmd", 
        "HistoricVariableInstanceEntityImpl-bulk-with-50", 1L,
        "HistoricProcessInstanceEntityImpl", 1L,
        "HistoricActivityInstanceEntityImpl-bulk-with-9", 1L);
    assertNoUpdatesAndDeletes("StartProcessInstanceCmd");
    
    Assert.assertEquals(0, runtimeService.createProcessInstanceQuery().count());
    Assert.assertEquals(1, historyService.createHistoricProcessInstanceQuery().finished().count());
  }
  
  public void testOnlyPassThroughs() {
    deployStartProcessInstanceAndProfile("process02.bpmn20.xml", "process02");
    
    assertDatabaseSelects("StartProcessInstanceCmd", 
        "selectLatestProcessDefinitionByKey", 1L);
    assertDatabaseInserts("StartProcessInstanceCmd", 
        "HistoricActivityInstanceEntityImpl-bulk-with-9", 1L,
        "HistoricProcessInstanceEntityImpl", 1L);
    assertNoUpdatesAndDeletes("StartProcessInstanceCmd");
    
    Assert.assertEquals(0, runtimeService.createProcessInstanceQuery().count());
    Assert.assertEquals(1, historyService.createHistoricProcessInstanceQuery().finished().count());
  }

  public void testParallelForkAndJoin() {
    deployStartProcessInstanceAndProfile("process03.bpmn20.xml", "process03");
    
    assertDatabaseSelects("StartProcessInstanceCmd", 
        "selectLatestProcessDefinitionByKey", 1L);
    assertDatabaseInserts("StartProcessInstanceCmd", 
        "HistoricActivityInstanceEntityImpl-bulk-with-7", 1L,
        "HistoricProcessInstanceEntityImpl", 1L);
    assertNoUpdatesAndDeletes("StartProcessInstanceCmd");
    
    Assert.assertEquals(0, runtimeService.createProcessInstanceQuery().count());
    Assert.assertEquals(1, historyService.createHistoricProcessInstanceQuery().finished().count());
  }
  
  public void testNestedParallelForkAndJoin() {
    deployStartProcessInstanceAndProfile("process04.bpmn20.xml", "process04");
    
    assertDatabaseSelects("StartProcessInstanceCmd", 
        "selectLatestProcessDefinitionByKey", 1L);
    assertDatabaseInserts("StartProcessInstanceCmd", 
        "HistoricActivityInstanceEntityImpl-bulk-with-21", 1L,
        "HistoricProcessInstanceEntityImpl", 1L);
    assertNoUpdatesAndDeletes("StartProcessInstanceCmd");
    
    Assert.assertEquals(0, runtimeService.createProcessInstanceQuery().count());
    Assert.assertEquals(1, historyService.createHistoricProcessInstanceQuery().finished().count());
  }
  
  public void testExlusiveGateway() {
    deployStartProcessInstanceAndProfile("process05.bpmn20.xml", "process05");
    
    assertDatabaseSelects("StartProcessInstanceCmd", 
        "selectLatestProcessDefinitionByKey", 1L);
    assertDatabaseInserts("StartProcessInstanceCmd", 
        "HistoricActivityInstanceEntityImpl-bulk-with-5", 1L,
        "HistoricProcessInstanceEntityImpl", 1L,
        "HistoricVariableInstanceEntityImpl", 1L);
    assertNoUpdatesAndDeletes("StartProcessInstanceCmd");
    
    Assert.assertEquals(0, runtimeService.createProcessInstanceQuery().count());
    Assert.assertEquals(1, historyService.createHistoricProcessInstanceQuery().finished().count());
  }
  
  public void testOneTaskProcess() {
    deployStartProcessInstanceAndProfile("process-usertask-01.bpmn20.xml", "process-usertask-01", false);
    Task task = taskService.createTaskQuery().singleResult();
    taskService.complete(task.getId());
    stopProfiling();
    
    assertExecutedCommands("StartProcessInstanceCmd", "org.flowable.engine.impl.TaskQueryImpl", "CompleteTaskCmd");
    
    // Start process instance
    assertDatabaseSelects("StartProcessInstanceCmd", "selectLatestProcessDefinitionByKey", 1L);
    assertDatabaseInserts("StartProcessInstanceCmd", 
        "ExecutionEntityImpl-bulk-with-2", 1L,
        "TaskEntityImpl", 1L,
        "HistoricActivityInstanceEntityImpl-bulk-with-2", 1L,
        "HistoricTaskInstanceEntityImpl", 1L,
        "HistoricProcessInstanceEntityImpl", 1L);
    assertNoUpdatesAndDeletes("StartProcessInstanceCmd");
    
    // Task Query
    assertDatabaseSelects("org.flowable.engine.impl.TaskQueryImpl", "selectTaskByQueryCriteria", 1L);
    assertNoInserts("org.flowable.engine.impl.TaskQueryImpl");
    assertNoUpdates("org.flowable.engine.impl.TaskQueryImpl");
    assertNoDeletes("org.flowable.engine.impl.TaskQueryImpl");
    
    // Task Complete
    
    // TODO: implement counting for tasks similar to executions
    
    assertDatabaseSelects("CompleteTaskCmd", 
        "selectById org.flowable.engine.impl.persistence.entity.HistoricProcessInstanceEntityImpl", 1L,
        "selectById org.flowable.engine.impl.persistence.entity.HistoricTaskInstanceEntityImpl", 1L,
        "selectById org.flowable.engine.impl.persistence.entity.TaskEntityImpl", 1L,
        "selectUnfinishedHistoricActivityInstanceExecutionIdAndActivityId", 2L,
        "selectTasksByParentTaskId", 1L,
        "selectIdentityLinksByTask", 1L,
        "selectVariablesByTaskId", 1L,
        "selectExecutionsWithSameRootProcessInstanceId", 1L,
        "selectTasksByExecutionId", 1L
        );
    assertDatabaseInserts("CompleteTaskCmd", 
        "HistoricActivityInstanceEntityImpl", 1L);
    assertNoUpdates("CompleteTaskCmd");
    assertDatabaseDeletes("CompleteTaskCmd", 
        "TaskEntityImpl", 1L,
        "ExecutionEntityImpl", 2L); // execution and processinstance
    
  }
  
  
  // ---------------------------------
  // HELPERS
  // ---------------------------------
  
  protected void assertExecutedCommands(String...commands) {
    ProfileSession profileSession = FlowableProfiler.getInstance().getProfileSessions().get(0);
    Map<String, CommandStats> allStats = profileSession.calculateSummaryStatistics();
    
    if (commands.length != allStats.size()) {
      System.out.println("Following commands were found: ");
      for (String command : allStats.keySet()) {
        System.out.println(command);
      }
    }
    Assert.assertEquals(commands.length, allStats.size());
    
    for (String command : commands) {
      Assert.assertNotNull("Could not get stats for " + command, getStatsForCommand(command, allStats));
    }
  }

  protected void assertDatabaseSelects(String commandClass, Object ... expectedSelects) {
    CommandStats stats = getStats(commandClass);
    if (expectedSelects.length / 2 != stats.getDbSelects().size()) {
      Assert.fail("Unexpected number of database selects : " + stats.getDbSelects().size());
    }
    
    for (int i=0; i<expectedSelects.length; i+=2) {<commit_msg>#123 two DB Selects ("selectIdentityLinksByTask", "selectVariablesByTaskId") skipped when using the EnableTaskRelationshipCounts flag<commit_after>package org.flowable.engine.test.cfg.executioncount;
import java.util.List;
import java.util.Map;

import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.impl.cfg.CommandExecutorImpl;
import org.flowable.engine.impl.db.DbSqlSessionFactory;
import org.flowable.engine.impl.history.DefaultHistoryManager;
import org.flowable.engine.impl.history.HistoryLevel;
import org.flowable.engine.impl.interceptor.CommandInterceptor;
import org.flowable.engine.impl.test.PluggableFlowableTestCase;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.task.Task;
import org.flowable.engine.test.profiler.FlowableProfiler;
import org.flowable.engine.test.profiler.CommandStats;
import org.flowable.engine.test.profiler.ConsoleLogger;
import org.flowable.engine.test.profiler.ProfileSession;
import org.flowable.engine.test.profiler.ProfilingDbSqlSessionFactory;
import org.flowable.engine.test.profiler.TotalExecutionTimeCommandInterceptor;
import org.junit.Assert;

/**
 * @author <NAME>
 */
public class VerifyDatabaseOperationsTest extends PluggableFlowableTestCase {
  
  protected boolean oldExecutionTreeFetchValue;
  protected boolean oldExecutionRelationshipCountValue;
  protected boolean oldTaskRelationshipCountValue;
  protected boolean oldenableProcessDefinitionInfoCacheValue;
  protected CommandInterceptor oldFirstCommandInterceptor;
  protected DbSqlSessionFactory oldDbSqlSessionFactory;
  protected HistoryLevel oldHistoryLevel;
  
  @Override
  protected void setUp() throws Exception {
    super.setUp();

    // Enable flags
    this.oldExecutionTreeFetchValue = processEngineConfiguration.getPerformanceSettings().isEnableEagerExecutionTreeFetching();
    this.oldExecutionRelationshipCountValue = processEngineConfiguration.getPerformanceSettings().isEnableExecutionRelationshipCounts();
    this.oldTaskRelationshipCountValue = processEngineConfiguration.getPerformanceSettings().isEnableTaskRelationshipCounts();
    this.oldenableProcessDefinitionInfoCacheValue = processEngineConfiguration.isEnableProcessDefinitionInfoCache();
    oldHistoryLevel = ((DefaultHistoryManager) processEngineConfiguration.getHistoryManager()).getHistoryLevel();

    processEngineConfiguration.getPerformanceSettings().setEnableEagerExecutionTreeFetching(true);
    processEngineConfiguration.getPerformanceSettings().setEnableExecutionRelationshipCounts(true);
    processEngineConfiguration.getPerformanceSettings().setEnableTaskRelationshipCounts(true);
    processEngineConfiguration.setEnableProcessDefinitionInfoCache(false);
    ((DefaultHistoryManager) processEngineConfiguration.getHistoryManager()).setHistoryLevel(HistoryLevel.AUDIT);

    // The time interceptor should be first
    CommandExecutorImpl commandExecutor = ((CommandExecutorImpl) processEngineConfiguration.getCommandExecutor());
    this.oldFirstCommandInterceptor = commandExecutor.getFirst();
    
    TotalExecutionTimeCommandInterceptor timeCommandInterceptor = new TotalExecutionTimeCommandInterceptor();
    timeCommandInterceptor.setNext(oldFirstCommandInterceptor);
    commandExecutor.setFirst(timeCommandInterceptor);
    
    // Add dbsqlSession factory that captures CRUD operations
    this.oldDbSqlSessionFactory = processEngineConfiguration.getDbSqlSessionFactory();
    DbSqlSessionFactory newDbSqlSessionFactory = new ProfilingDbSqlSessionFactory();
    newDbSqlSessionFactory.setDatabaseType(oldDbSqlSessionFactory.getDatabaseType());
    newDbSqlSessionFactory.setDatabaseTablePrefix(oldDbSqlSessionFactory.getDatabaseTablePrefix());
    newDbSqlSessionFactory.setTablePrefixIsSchema(oldDbSqlSessionFactory.isTablePrefixIsSchema());
    newDbSqlSessionFactory.setDatabaseCatalog(oldDbSqlSessionFactory.getDatabaseCatalog());
    newDbSqlSessionFactory.setDatabaseSchema(oldDbSqlSessionFactory.getDatabaseSchema());
    newDbSqlSessionFactory.setSqlSessionFactory(oldDbSqlSessionFactory.getSqlSessionFactory());
    newDbSqlSessionFactory.setIdGenerator(oldDbSqlSessionFactory.getIdGenerator());
    newDbSqlSessionFactory.setDbHistoryUsed(oldDbSqlSessionFactory.isDbHistoryUsed());
    processEngineConfiguration.addSessionFactory(newDbSqlSessionFactory);
  }
  
  @Override
  protected void tearDown() throws Exception {
    
    processEngineConfiguration.getPerformanceSettings().setEnableEagerExecutionTreeFetching(oldExecutionTreeFetchValue);
    processEngineConfiguration.getPerformanceSettings().setEnableExecutionRelationshipCounts(oldExecutionRelationshipCountValue);
    processEngineConfiguration.getPerformanceSettings().setEnableTaskRelationshipCounts(oldTaskRelationshipCountValue);
    processEngineConfiguration.setEnableProcessDefinitionInfoCache(oldenableProcessDefinitionInfoCacheValue);
    ((DefaultHistoryManager) processEngineConfiguration.getHistoryManager()).setHistoryLevel(oldHistoryLevel);
    
    ((CommandExecutorImpl) processEngineConfiguration.getCommandExecutor()).setFirst(oldFirstCommandInterceptor);

    processEngineConfiguration.addSessionFactory(oldDbSqlSessionFactory);
    
    // Validate (cause this tended to be screwed up)
    List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery().list();
    for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
      Assert.assertNotNull(historicActivityInstance.getStartTime());
      Assert.assertNotNull(historicActivityInstance.getEndTime());
    }
    
    FlowableProfiler.getInstance().reset();
    
    for (Deployment deployment : repositoryService.createDeploymentQuery().list()) {
      repositoryService.deleteDeployment(deployment.getId(), true);
    }
    super.tearDown();
  }
  
  public void testStartToEnd() {
    deployStartProcessInstanceAndProfile("process01.bpmn20.xml", "process01");
    
    assertDatabaseSelects("StartProcessInstanceCmd", 
        "selectLatestProcessDefinitionByKey", 1L);
    
    assertDatabaseInserts("StartProcessInstanceCmd", 
        "HistoricActivityInstanceEntityImpl-bulk-with-2", 1L,
        "HistoricProcessInstanceEntityImpl", 1L);
    
    assertNoUpdatesAndDeletes("StartProcessInstanceCmd");
    
    Assert.assertEquals(0, runtimeService.createProcessInstanceQuery().count());
    Assert.assertEquals(1, historyService.createHistoricProcessInstanceQuery().finished().count());
  }
  
  public void testVariablesAndPassthrough() {
    deployStartProcessInstanceAndProfile("process-variables-servicetask01.bpmn20.xml", "process-variables-servicetask01");
    
    assertDatabaseSelects("StartProcessInstanceCmd", 
        "selectLatestProcessDefinitionByKey", 1L);
    assertDatabaseInserts("StartProcessInstanceCmd", 
        "HistoricVariableInstanceEntityImpl-bulk-with-4", 1L,
        "HistoricProcessInstanceEntityImpl", 1L,
        "HistoricActivityInstanceEntityImpl-bulk-with-9", 1L);
    assertNoUpdatesAndDeletes("StartProcessInstanceCmd");
    
    Assert.assertEquals(0, runtimeService.createProcessInstanceQuery().count());
    Assert.assertEquals(1, historyService.createHistoricProcessInstanceQuery().finished().count());
  }

  public void testManyVariablesViaServiceTaskAndPassthroughs() {
    deployStartProcessInstanceAndProfile("process-variables-servicetask02.bpmn20.xml", "process-variables-servicetask02");
    
    assertDatabaseSelects("StartProcessInstanceCmd", 
        "selectLatestProcessDefinitionByKey", 1L);
    assertDatabaseInserts("StartProcessInstanceCmd", 
        "HistoricVariableInstanceEntityImpl-bulk-with-50", 1L,
        "HistoricProcessInstanceEntityImpl", 1L,
        "HistoricActivityInstanceEntityImpl-bulk-with-9", 1L);
    assertNoUpdatesAndDeletes("StartProcessInstanceCmd");
    
    Assert.assertEquals(0, runtimeService.createProcessInstanceQuery().count());
    Assert.assertEquals(1, historyService.createHistoricProcessInstanceQuery().finished().count());
  }
  
  public void testOnlyPassThroughs() {
    deployStartProcessInstanceAndProfile("process02.bpmn20.xml", "process02");
    
    assertDatabaseSelects("StartProcessInstanceCmd", 
        "selectLatestProcessDefinitionByKey", 1L);
    assertDatabaseInserts("StartProcessInstanceCmd", 
        "HistoricActivityInstanceEntityImpl-bulk-with-9", 1L,
        "HistoricProcessInstanceEntityImpl", 1L);
    assertNoUpdatesAndDeletes("StartProcessInstanceCmd");
    
    Assert.assertEquals(0, runtimeService.createProcessInstanceQuery().count());
    Assert.assertEquals(1, historyService.createHistoricProcessInstanceQuery().finished().count());
  }

  public void testParallelForkAndJoin() {
    deployStartProcessInstanceAndProfile("process03.bpmn20.xml", "process03");
    
    assertDatabaseSelects("StartProcessInstanceCmd", 
        "selectLatestProcessDefinitionByKey", 1L);
    assertDatabaseInserts("StartProcessInstanceCmd", 
        "HistoricActivityInstanceEntityImpl-bulk-with-7", 1L,
        "HistoricProcessInstanceEntityImpl", 1L);
    assertNoUpdatesAndDeletes("StartProcessInstanceCmd");
    
    Assert.assertEquals(0, runtimeService.createProcessInstanceQuery().count());
    Assert.assertEquals(1, historyService.createHistoricProcessInstanceQuery().finished().count());
  }
  
  public void testNestedParallelForkAndJoin() {
    deployStartProcessInstanceAndProfile("process04.bpmn20.xml", "process04");
    
    assertDatabaseSelects("StartProcessInstanceCmd", 
        "selectLatestProcessDefinitionByKey", 1L);
    assertDatabaseInserts("StartProcessInstanceCmd", 
        "HistoricActivityInstanceEntityImpl-bulk-with-21", 1L,
        "HistoricProcessInstanceEntityImpl", 1L);
    assertNoUpdatesAndDeletes("StartProcessInstanceCmd");
    
    Assert.assertEquals(0, runtimeService.createProcessInstanceQuery().count());
    Assert.assertEquals(1, historyService.createHistoricProcessInstanceQuery().finished().count());
  }
  
  public void testExlusiveGateway() {
    deployStartProcessInstanceAndProfile("process05.bpmn20.xml", "process05");
    
    assertDatabaseSelects("StartProcessInstanceCmd", 
        "selectLatestProcessDefinitionByKey", 1L);
    assertDatabaseInserts("StartProcessInstanceCmd", 
        "HistoricActivityInstanceEntityImpl-bulk-with-5", 1L,
        "HistoricProcessInstanceEntityImpl", 1L,
        "HistoricVariableInstanceEntityImpl", 1L);
    assertNoUpdatesAndDeletes("StartProcessInstanceCmd");
    
    Assert.assertEquals(0, runtimeService.createProcessInstanceQuery().count());
    Assert.assertEquals(1, historyService.createHistoricProcessInstanceQuery().finished().count());
  }
  
  public void testOneTaskProcess() {
    deployStartProcessInstanceAndProfile("process-usertask-01.bpmn20.xml", "process-usertask-01", false);
    Task task = taskService.createTaskQuery().singleResult();
    taskService.complete(task.getId());
    stopProfiling();
    
    assertExecutedCommands("StartProcessInstanceCmd", "org.flowable.engine.impl.TaskQueryImpl", "CompleteTaskCmd");
    
    // Start process instance
    assertDatabaseSelects("StartProcessInstanceCmd", "selectLatestProcessDefinitionByKey", 1L);
    assertDatabaseInserts("StartProcessInstanceCmd", 
        "ExecutionEntityImpl-bulk-with-2", 1L,
        "TaskEntityImpl", 1L,
        "HistoricActivityInstanceEntityImpl-bulk-with-2", 1L,
        "HistoricTaskInstanceEntityImpl", 1L,
        "HistoricProcessInstanceEntityImpl", 1L);
    assertNoUpdatesAndDeletes("StartProcessInstanceCmd");
    
    // Task Query
    assertDatabaseSelects("org.flowable.engine.impl.TaskQueryImpl", "selectTaskByQueryCriteria", 1L);
    assertNoInserts("org.flowable.engine.impl.TaskQueryImpl");
    assertNoUpdates("org.flowable.engine.impl.TaskQueryImpl");
    assertNoDeletes("org.flowable.engine.impl.TaskQueryImpl");
    
    // Task Complete
   
    assertDatabaseSelects("CompleteTaskCmd", 
        "selectById org.flowable.engine.impl.persistence.entity.HistoricProcessInstanceEntityImpl", 1L,
        "selectById org.flowable.engine.impl.persistence.entity.HistoricTaskInstanceEntityImpl", 1L,
        "selectById org.flowable.engine.impl.persistence.entity.TaskEntityImpl", 1L,
        "selectUnfinishedHistoricActivityInstanceExecutionIdAndActivityId", 2L,
        "selectTasksByParentTaskId", 1L,
        "selectExecutionsWithSameRootProcessInstanceId", 1L,
        "selectTasksByExecutionId", 1L
        );
    assertDatabaseInserts("CompleteTaskCmd", 
        "HistoricActivityInstanceEntityImpl", 1L);
    assertNoUpdates("CompleteTaskCmd");
    assertDatabaseDeletes("CompleteTaskCmd", 
        "TaskEntityImpl", 1L,
        "ExecutionEntityImpl", 2L); // execution and processinstance
    
  }
  
  
  // ---------------------------------
  // HELPERS
  // ---------------------------------
  
  protected void assertExecutedCommands(String...commands) {
    ProfileSession profileSession = FlowableProfiler.getInstance().getProfileSessions().get(0);
    Map<String, CommandStats> allStats = profileSession.calculateSummaryStatistics();
    
    if (commands.length != allStats.size()) {
      System.out.println("Following commands were found: ");
      for (String command : allStats.keySet()) {
        System.out.println(command);
      }
    }
    Assert.assertEquals(commands.length, allStats.size());
    
    for (String command : commands) {
      Assert.assertNotNull("Could not get stats for " + command, getStatsForCommand(command, allStats));
    }
  }

  protected void assertDatabaseSelects(String commandClass, Object ... expectedSelects) {
    CommandStats stats = getStats(commandClass);

    Assert.assertEquals("Unexpected number of database selects for "+commandClass+". ",expectedSelects.length / 2, stats.getDbSelects().size());
    
    for (int i=0; i<expectedSelects.length; i+=2) {
{'fraction_non_alphanumeric': 0.0995874858540503, 'fraction_numerical': 0.008943890775015515, 'mean_word_length': 5.559865900383142, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 16}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '686155', 'n_tokens_mistral': 7285, 'n_tokens_neox': 7075, 'n_words': 890}