/* * Copyright 2016 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * * 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.jbpm.test.container.test.ejbservices.tx; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.naming.InitialContext; import javax.transaction.Status; import javax.transaction.UserTransaction; import org.assertj.core.api.Assertions; import org.drools.core.command.runtime.rule.FireAllRulesCommand; import org.jbpm.services.api.model.NodeInstanceDesc; import org.jbpm.services.api.model.ProcessInstanceDesc; import org.jbpm.test.container.AbstractRuntimeEJBServicesTest; import org.jbpm.test.container.groups.EAP; import org.jbpm.test.container.groups.WAS; import org.jbpm.test.container.groups.WLS; import org.jbpm.test.container.listeners.TrackingAgendaEventListener; import org.junit.Before; import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runners.MethodSorters; import org.kie.api.runtime.manager.RuntimeEngine; import org.kie.api.runtime.manager.RuntimeManager; import org.kie.api.runtime.process.ProcessInstance; import org.kie.api.task.model.TaskSummary; import org.kie.internal.query.QueryContext; import org.kie.internal.query.QueryFilter; import org.kie.internal.runtime.manager.context.ProcessInstanceIdContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @FixMethodOrder(MethodSorters.NAME_ASCENDING) @Category({EAP.class, WLS.class, WAS.class}) public class ETransactionTest extends AbstractRuntimeEJBServicesTest { private static final String USER_TRANSACTION_NAME = "java:comp/UserTransaction"; private static final Logger LOGGER = LoggerFactory.getLogger(ETransactionTest.class); private static final String PROCESS_ID = "transactions"; @Before @Override public void deployKieJar() { if (kieJar == null) { kieJar = archive.deployTransactionKieJar().getIdentifier(); } } @Test public void testStartProcessCommit() throws Exception { UserTransaction ut = InitialContext.doLookup(USER_TRANSACTION_NAME); ut.begin(); Long processInstanceId = null; ProcessInstanceDesc processDesc = null; List<NodeInstanceDesc> processInstanceHistory = null; try { processInstanceId = startProcessInstance(PROCESS_ID); checkProcessInstanceIsActive(processInstanceId); } catch (Exception e) { ut.rollback(); throw e; } ut.commit(); checkProcessInstanceIsActive(processInstanceId); } @Test public void testStartProcessRollback() throws Exception { UserTransaction ut = InitialContext.doLookup(USER_TRANSACTION_NAME); ut.begin(); Long processInstanceId = null; ProcessInstanceDesc processDesc = null; List<NodeInstanceDesc> processInstanceHistory = null; try { processInstanceId = startProcessInstance(PROCESS_ID); checkProcessInstanceIsActive(processInstanceId); } catch (Exception e) { ut.rollback(); throw e; } ut.rollback(); try { processDesc = runtimeDataService.getProcessInstanceById(processInstanceId); Assertions.assertThat(processDesc).isNull(); processInstanceHistory = getProcessInstanceHistory(processInstanceId); Assertions.assertThat(processInstanceHistory).isNullOrEmpty(); } catch (NullPointerException npe) { LOGGER.error("Non-XA database thrown NPE on process started before rollback", npe); } } @Test public void testAbortProcessCommit() throws Exception { Long processInstanceId = startProcessInstance(PROCESS_ID); checkProcessInstanceIsActive(processInstanceId); UserTransaction ut = InitialContext.doLookup(USER_TRANSACTION_NAME); ut.begin(); try { processService.abortProcessInstance(processInstanceId); } catch (Exception e) { ut.rollback(); throw e; } ut.commit(); List<Integer> states = new ArrayList<Integer>(); states.add(ProcessInstance.STATE_ABORTED); Collection<ProcessInstanceDesc> processInstances = runtimeDataService.getProcessInstances(states, null, new QueryContext()); Assertions.assertThat(processInstances).isNotNull().hasSize(1); Assertions.assertThat(processInstances.iterator().next().getId()).isEqualTo(processInstanceId); } @Test public void testAbortProcessRollback() throws Exception { Long processInstanceId = startProcessInstance(PROCESS_ID); checkProcessInstanceIsActive(processInstanceId); UserTransaction ut = InitialContext.doLookup(USER_TRANSACTION_NAME); ut.begin(); try { processService.abortProcessInstance(processInstanceId); } catch (Exception e) { ut.rollback(); throw e; } ut.rollback(); ProcessInstance processInstance = processService.getProcessInstance(processInstanceId); Assertions.assertThat(processInstance).isNotNull(); Assertions.assertThat(processInstance.getId()).isEqualTo(processInstanceId); Assertions.assertThat(processInstance.getState()).isEqualTo(ProcessInstance.STATE_ACTIVE); } @Test public void testScript() throws Exception { Long processInstanceId = startProcessInstance(PROCESS_ID); UserTransaction ut = InitialContext.doLookup(USER_TRANSACTION_NAME); ut.begin(); try { processService.signalProcessInstance(processInstanceId, "start", "script"); Assertions.assertThat(hasNodeLeft(processInstanceId, "script")).isTrue(); } catch (Exception e) { ut.rollback(); throw e; } ut.rollback(); ut = InitialContext.doLookup(USER_TRANSACTION_NAME); ut.begin(); try { processService.signalProcessInstance(processInstanceId, "start", "script"); Assertions.assertThat(ut.getStatus()).isEqualTo(Status.STATUS_ACTIVE); } catch (Exception e) { ut.rollback(); throw e; } ut.commit(); Assertions.assertThat(hasNodeLeft(processInstanceId, "script")).isTrue(); processService.signalProcessInstance(processInstanceId, "finish", null); Assertions.assertThat(hasProcessInstanceCompleted(processInstanceId)).isTrue(); } @Test public void testRuleFlowGroup() throws Exception { TrackingAgendaEventListener agenda = new TrackingAgendaEventListener(); RuntimeManager manager = deploymentService.getRuntimeManager(kieJar); RuntimeEngine engine = manager.getRuntimeEngine(ProcessInstanceIdContext.get()); engine.getKieSession().addEventListener(agenda); Long processInstanceId = startProcessInstance(PROCESS_ID); UserTransaction ut = InitialContext.doLookup(USER_TRANSACTION_NAME); ut.begin(); processService.signalProcessInstance(processInstanceId, "start", "rfg"); Assertions.assertThat(hasNodeLeft(processInstanceId, "rfg")).isTrue(); ut.rollback(); agenda.clear(); processService.execute(kieJar, new FireAllRulesCommand()); Assertions.assertThat(agenda.isRuleFired("dummyRule")).isFalse(); agenda.clear(); ut = InitialContext.doLookup(USER_TRANSACTION_NAME); ut.begin(); processService.signalProcessInstance(processInstanceId, "start", "rfg"); ut.commit(); Assertions.assertThat(hasNodeLeft(processInstanceId, "rfg")).isTrue(); processService.execute(kieJar, new FireAllRulesCommand()); processService.signalProcessInstance(processInstanceId, "finish", null); Assertions.assertThat(agenda.isRuleFired("dummyRule")).isTrue(); Assertions.assertThat(hasProcessInstanceCompleted(processInstanceId)).isTrue(); } @Test public void testTimer() throws Exception { Long processInstanceId = startProcessInstance(PROCESS_ID); UserTransaction ut = InitialContext.doLookup(USER_TRANSACTION_NAME); ut.begin(); try { processService.signalProcessInstance(processInstanceId, "start", "timer"); Assertions.assertThat(hasNodeLeft(processInstanceId, "timer")).isTrue(); } catch (Exception e) { ut.rollback(); throw e; } ut.rollback(); ut = InitialContext.doLookup(USER_TRANSACTION_NAME); ut.begin(); try { processService.signalProcessInstance(processInstanceId, "start", "timer"); } catch (Exception e) { ut.rollback(); throw e; } ut.commit(); Thread.sleep(2000); //to make sure the timer is completed Assertions.assertThat(hasNodeLeft(processInstanceId, "timer")).isTrue(); Assertions.assertThat(hasNodeLeft(processInstanceId, "Timer")).isTrue(); processService.signalProcessInstance(processInstanceId, "finish", null); Assertions.assertThat(hasProcessInstanceCompleted(processInstanceId)).isTrue(); } @Test public void testHumanTask() throws Exception { Long processInstanceId = startProcessInstance(PROCESS_ID); UserTransaction ut = InitialContext.doLookup(USER_TRANSACTION_NAME); ut.begin(); List<TaskSummary> taskSummaries = null; try { processService.signalProcessInstance(processInstanceId, "start", "usertask"); taskSummaries = startAndCompleteHumanTask(processInstanceId); } catch (Exception e) { ut.rollback(); throw e; } ut.rollback(); Assertions.assertThat(runtimeDataService.getTaskById(taskSummaries.get(0).getId())).isNull(); ut = InitialContext.doLookup(USER_TRANSACTION_NAME); ut.begin(); try { processService.signalProcessInstance(processInstanceId, "start", "usertask"); taskSummaries = startAndCompleteHumanTask(processInstanceId); } catch (Exception e) { ut.rollback(); throw e; } ut.commit(); Assertions.assertThat(hasNodeLeft(processInstanceId, "User Task")).isTrue(); Assertions.assertThat(hasTaskCompleted(taskSummaries.get(0).getId())); Assertions.assertThat(hasProcessInstanceCompleted(processInstanceId)).isFalse(); } @Test public void testForLoop() throws Exception { Map<String, Object> params = new HashMap<String, Object>(); params.put("collection", Arrays.asList("hello world", "25", "false", "1234567891011121314151617181920", "")); Long processInstanceId = startProcessInstance(PROCESS_ID, params); UserTransaction ut = InitialContext.doLookup(USER_TRANSACTION_NAME); ut.begin(); try { processService.signalProcessInstance(processInstanceId, "start", "forloop"); Assertions.assertThat(hasNodeLeft(processInstanceId, "forloop")).isTrue(); } catch (Exception e) { ut.rollback(); throw e; } ut.rollback(); ut = InitialContext.doLookup(USER_TRANSACTION_NAME); ut.begin(); try { processService.signalProcessInstance(processInstanceId, "start", "forloop"); } catch (Exception e) { ut.rollback(); throw e; } ut.commit(); Assertions.assertThat(hasNodeLeft(processInstanceId, "forloop")).isTrue(); Assertions.assertThat(hasNodeLeft(processInstanceId, "Multiple Instances")).isTrue(); Assertions.assertThat(hasProcessInstanceCompleted(processInstanceId)).isFalse(); } @Test public void testEmbedded() throws Exception { Long processInstanceId = startProcessInstance(PROCESS_ID); UserTransaction ut = InitialContext.doLookup(USER_TRANSACTION_NAME); ut.begin(); try { processService.signalProcessInstance(processInstanceId, "start", "embedded"); Assertions.assertThat(hasNodeLeft(processInstanceId, "embedded")).isTrue(); } catch (Exception e) { ut.rollback(); throw e; } ut.rollback(); ut = InitialContext.doLookup(USER_TRANSACTION_NAME); ut.begin(); try { processService.signalProcessInstance(processInstanceId, "start", "embedded"); } catch (Exception e) { ut.rollback(); throw e; } ut.commit(); Assertions.assertThat(hasNodeLeft(processInstanceId, "embedded")).isTrue(); Assertions.assertThat(hasProcessInstanceCompleted(processInstanceId)).isFalse(); } private void checkProcessInstanceIsActive(Long processInstanceId) { ProcessInstanceDesc processDesc = runtimeDataService.getProcessInstanceById(processInstanceId); Assertions.assertThat(processDesc).isNotNull(); Assertions.assertThat(processDesc.getState()).isEqualTo(ProcessInstance.STATE_ACTIVE); List<NodeInstanceDesc> processInstanceHistory = getProcessInstanceHistory(processInstanceId); Assertions.assertThat(processInstanceHistory).isNotNull().isNotEmpty(); } private List<TaskSummary> startAndCompleteHumanTask(Long processInstanceId) { List<TaskSummary> taskSummaries = runtimeDataService.getTasksAssignedAsPotentialOwner("john", new QueryFilter()); Assertions.assertThat(taskSummaries).isNotNull().hasSize(1); userTaskService.start(taskSummaries.get(0).getId(), "john"); userTaskService.complete(taskSummaries.get(0).getId(), "john", new HashMap<String, Object>()); Assertions.assertThat(hasNodeLeft(processInstanceId, "User Task")).isTrue(); return taskSummaries; } }