/*
* 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;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.transaction.Status;
import javax.transaction.UserTransaction;
import org.assertj.core.api.Assertions;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.TargetsContainer;
import org.jboss.shrinkwrap.api.Archive;
import org.jboss.shrinkwrap.api.spec.WebArchive;
import org.jbpm.test.container.JbpmContainerTest;
import org.jbpm.test.container.archive.LocalTransactions;
import org.jbpm.test.container.groups.EAP;
import org.jbpm.test.container.groups.EWS;
import org.jbpm.test.container.groups.WAS;
import org.jbpm.test.container.groups.WLS;
import org.jbpm.test.container.handlers.ListWorkItemHandler;
import org.jbpm.test.container.listeners.TrackingAgendaEventListener;
import org.jbpm.test.container.listeners.TrackingProcessEventListener;
import org.jbpm.test.container.tools.KieUtils;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.kie.api.KieBase;
import org.kie.api.io.Resource;
import org.kie.api.runtime.Environment;
import org.kie.api.runtime.EnvironmentName;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.process.ProcessInstance;
import org.kie.internal.KnowledgeBaseFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* jBPM transaction test. This test uses the transaction(s) provided by the container in
* which the engine is running.
*
*/
@Category({EAP.class, WLS.class, WAS.class, EWS.class})
public class TransactionsTest extends JbpmContainerTest {
private static final Logger LOGGER = LoggerFactory.getLogger(TransactionsTest.class);
private static final List<Resource> RESOURCES = new ArrayList<Resource>();
private static LocalTransactions lt = new LocalTransactions();
/*
* Initialize the resource list.
*/
static {
RESOURCES.add(lt.getResource(LocalTransactions.BPMN_TRANSACTIONS));
RESOURCES.add(lt.getResource(LocalTransactions.BPMN_HELLO_WORLD));
RESOURCES.add(lt.getResource(LocalTransactions.RULES_TRANSACTIONS));
}
public TransactionsTest() {
persistence = true;
}
@Deployment(name = "LocalTransactions")
@TargetsContainer(REMOTE_CONTAINER)
public static Archive<?> deployLocalTransactions() {
WebArchive war = lt.buildArchive();
war.addClass(TransactionsTest.class);
war.addClass(JbpmContainerTest.class);
System.out.println("### Deploying war '" + war + "'");
return war;
}
// ---------------------------- Test Case Members
@Test
public void testStartProcessCommit() throws Exception {
KieSession ksession = createJPASession(getKnowledgeBase());
UserTransaction ut = getUserTransaction();
ut.begin();
long processId = ksession.startProcess(LocalTransactions.PROCESS_TRANSACTIONS).getId();
Assertions.assertThat(ksession.getProcessInstance(processId)).isNotNull();
Assertions.assertThat((long) ksession.getProcessInstance(processId).getState()).isEqualTo((long) ProcessInstance.STATE_ACTIVE);
ut.commit();
ksession = reloadSession(ksession);
Assertions.assertThat(ksession.getProcessInstance(processId)).isNotNull();
Assertions.assertThat((long) ksession.getProcessInstance(processId).getState()).isEqualTo((long) ProcessInstance.STATE_ACTIVE);
}
@Test
public void testStartProcessRollback() throws Exception {
KieSession ksession = createJPASession(getKnowledgeBase());
UserTransaction ut = getUserTransaction();
ut.begin();
long processId = ksession.startProcess(LocalTransactions.PROCESS_TRANSACTIONS).getId();
Assertions.assertThat(ksession.getProcessInstance(processId)).isNotNull();
Assertions.assertThat((long) ksession.getProcessInstance(processId).getState()).isEqualTo((long) ProcessInstance.STATE_ACTIVE);
ut.rollback();
System.out.println(ksession.getIdentifier() + " " + ksession.toString());
ksession = reloadSession(ksession);
System.out.println(ksession.getIdentifier() + " " + ksession.toString());
try {
ProcessInstance pi = ksession.getProcessInstance(processId);
Assertions.assertThat(pi).isNull();
} catch (NullPointerException npe) {
LOGGER.error("Non-XA database thrown NPE on process started before rollback", npe);
}
}
@Test
public void testAbortProcessCommit() throws Exception {
KieSession ksession = createJPASession(getKnowledgeBase());
long processId = ksession.startProcess(LocalTransactions.PROCESS_TRANSACTIONS).getId();
TrackingProcessEventListener listener = new TrackingProcessEventListener();
ksession.addEventListener(listener);
Assertions.assertThat((long) ksession.getProcessInstance(processId).getState()).isEqualTo((long) ProcessInstance.STATE_ACTIVE);
UserTransaction ut = getUserTransaction();
ut.begin();
ksession.abortProcessInstance(processId);
ut.commit();
ksession = reloadSession(ksession);
Assertions.assertThat(ksession.getProcessInstance(processId)).isNull();
Assertions.assertThat(listener.wasProcessAborted(LocalTransactions.PROCESS_TRANSACTIONS)).isTrue();
}
@Test
public void testAbortProcessRollback() throws Exception {
KieSession ksession = createJPASession(getKnowledgeBase());
long processId = ksession.startProcess(LocalTransactions.PROCESS_TRANSACTIONS).getId();
Assertions.assertThat(ksession.getProcessInstance(processId)).isNotNull();
Assertions.assertThat((long) ksession.getProcessInstance(processId).getState()).isEqualTo((long) ProcessInstance.STATE_ACTIVE);
UserTransaction ut = getUserTransaction();
ut.begin();
ksession.abortProcessInstance(processId);
ut.rollback();
ksession = reloadSession(ksession);
Assertions.assertThat(ksession.getProcessInstance(processId)).isNotNull();
Assertions.assertThat((long) ksession.getProcessInstance(processId).getState()).isEqualTo((long) ProcessInstance.STATE_ACTIVE);
}
@Test
public void testScript() throws Exception {
TrackingProcessEventListener process = new TrackingProcessEventListener();
KieSession ksession = createJPASession(getKnowledgeBase());
ksession.addEventListener(process);
long processId = ksession.startProcess(LocalTransactions.PROCESS_TRANSACTIONS).getId();
UserTransaction ut = getUserTransaction();
ut.begin();
ksession.signalEvent("start", "script", processId);
Assertions.assertThat(process.wasNodeLeft("script")).isTrue();
ut.rollback();
process.clear();
ksession = reloadSession(ksession);
ksession.addEventListener(process);
ut = getUserTransaction();
ut.begin();
ksession.signalEvent("start", "script", processId);
Thread.sleep(1000);
Assertions.assertThat((long) ut.getStatus()).isEqualTo((long) Status.STATUS_ACTIVE);
ut.commit();
Assertions.assertThat(process.wasNodeLeft("script")).isTrue();
ksession.signalEvent("finish", null, processId);
Thread.sleep(1000);
Assertions.assertThat(process.wasProcessCompleted(LocalTransactions.PROCESS_TRANSACTIONS)).isTrue();
}
@Test
public void testRuleflowGroup() throws Exception {
TrackingProcessEventListener process = new TrackingProcessEventListener();
TrackingAgendaEventListener agenda = new TrackingAgendaEventListener();
KieSession ksession = createJPASession(getKnowledgeBase());
ksession.addEventListener(process);
ksession.addEventListener(agenda);
long processId = ksession.startProcess(LocalTransactions.PROCESS_TRANSACTIONS).getId();
UserTransaction ut = getUserTransaction();
ut.begin();
ksession.signalEvent("start", "rfg", processId);
Assertions.assertThat(process.wasNodeLeft("rfg")).isTrue();
ut.rollback();
Thread.sleep(600);
process.clear();
agenda.clear();
ksession = reloadSession(ksession);
ksession.addEventListener(process);
ksession.addEventListener(agenda);
ksession.fireAllRules();
Assertions.assertThat(agenda.isRuleFired("dummyRule")).isFalse();
agenda.clear();
process.clear();
ut = getUserTransaction();
ut.begin();
ksession.signalEvent("start", "rfg", processId);
Thread.sleep(1000);
ut.commit();
Assertions.assertThat(process.wasNodeLeft("rfg")).isTrue();
ksession.fireAllRules();
ksession.signalEvent("finish", null, processId);
Thread.sleep(1000);
Assertions.assertThat(agenda.isRuleFired("dummyRule")).isTrue();
Assertions.assertThat(process.wasProcessCompleted(LocalTransactions.PROCESS_TRANSACTIONS)).isTrue();
}
@Test
public void testTimer() throws Exception {
TrackingProcessEventListener process = new TrackingProcessEventListener();
KieSession ksession = createJPASession(getKnowledgeBase());
ksession.addEventListener(process);
long processId = ksession.startProcess(LocalTransactions.PROCESS_TRANSACTIONS).getId();
UserTransaction ut = getUserTransaction();
ut.begin();
ksession.signalEvent("start", "timer", processId);
Assertions.assertThat(process.wasNodeLeft("timer")).isTrue();
ut.rollback();
Thread.sleep(600);
process.clear();
ksession = reloadSession(ksession);
ksession.addEventListener(process);
ut = getUserTransaction();
ut.begin();
ksession.signalEvent("start", "timer", processId);
ut.commit();
Thread.sleep(1000);
Assertions.assertThat(process.wasNodeLeft("timer")).isTrue();
ksession.signalEvent("finish", null, processId);
Assertions.assertThat(process.wasProcessCompleted(LocalTransactions.PROCESS_TRANSACTIONS)).isTrue();
}
@Test
public void testUsertask() throws Exception {
TrackingProcessEventListener process = new TrackingProcessEventListener();
KieSession ksession = createJPASession(getKnowledgeBase());
ksession.addEventListener(process);
ListWorkItemHandler handler = new ListWorkItemHandler();
ksession.getWorkItemManager().registerWorkItemHandler("Human Task", handler);
long processId = ksession.startProcess(LocalTransactions.PROCESS_TRANSACTIONS).getId();
UserTransaction ut = getUserTransaction();
ut.begin();
ksession.signalEvent("start", "usertask", processId);
Assertions.assertThat(process.wasNodeLeft("usertask")).isTrue();
Assertions.assertThat((long) handler.getWorkItems().size()).isEqualTo((long) 1);
ut.rollback();
// human tasks are not aborted (as that would not cause the task to be
// cancelled
process.clear();
ksession = reloadSession(ksession);
ksession.getWorkItemManager().registerWorkItemHandler("Human Task", handler);
ksession.addEventListener(process);
ut = getUserTransaction();
ut.begin();
ksession.signalEvent("start", "usertask", processId);
ut.commit();
Thread.sleep(1000);
Assertions.assertThat((long) handler.getWorkItems().size()).isEqualTo((long) 2);
Assertions.assertThat((long) handler.getWorkItems().size()).isEqualTo((long) 2);
Assertions.assertThat(process.wasNodeLeft("usertask")).isTrue();
Assertions.assertThat(process.wasNodeTriggered("User Task")).isTrue();
Assertions.assertThat(process.wasNodeLeft("User Task")).isFalse();
Assertions.assertThat(process.wasProcessCompleted(LocalTransactions.PROCESS_TRANSACTIONS)).isFalse();
}
@Test
public void testForloop() throws Exception {
TrackingProcessEventListener process = new TrackingProcessEventListener();
KieSession ksession = createJPASession(getKnowledgeBase());
ksession.addEventListener(process);
Map<String, Object> params = new HashMap<String, Object>();
params.put("collection", Arrays.asList("hello world", "25", "false", "1234567891011121314151617181920", ""));
long processId = ksession.startProcess(LocalTransactions.PROCESS_TRANSACTIONS, params).getId();
UserTransaction ut = getUserTransaction();
ut.begin();
ksession.signalEvent("start", "forloop", processId);
Thread.sleep(1000);
Assertions.assertThat(process.wasNodeLeft("forloop")).isTrue();
ut.rollback();
process.clear();
ksession = reloadSession(ksession);
ksession.addEventListener(process);
ut = getUserTransaction();
ut.begin();
ksession.signalEvent("start", "forloop", processId);
ut.commit();
Thread.sleep(5000);
Assertions.assertThat(process.wasNodeLeft("forloop")).isTrue();
Assertions.assertThat(process.wasNodeLeft("Multiple Instances")).isTrue();
Assertions.assertThat(process.wasProcessCompleted(LocalTransactions.PROCESS_TRANSACTIONS)).isFalse();
}
@Test
public void testEmbedded() throws Exception {
TrackingProcessEventListener process = new TrackingProcessEventListener();
KieSession ksession = createJPASession(getKnowledgeBase());
ksession.addEventListener(process);
long processId = ksession.startProcess(LocalTransactions.PROCESS_TRANSACTIONS).getId();
UserTransaction ut = getUserTransaction();
ut.begin();
ksession.signalEvent("start", "embedded", processId);
Thread.sleep(1000);
Assertions.assertThat(process.wasNodeLeft("embedded")).isTrue();
ut.rollback();
process.clear();
ksession = reloadSession(ksession);
ksession.addEventListener(process);
ut = getUserTransaction();
ut.begin();
ksession.signalEvent("start", "embedded", processId);
ut.commit();
Thread.sleep(5000);
Assertions.assertThat(process.wasNodeLeft("embedded")).isTrue();
Assertions.assertThat(process.wasProcessCompleted(LocalTransactions.PROCESS_TRANSACTIONS)).isFalse();
}
// ---------------------------- Private Members
private KieBase getKnowledgeBase() {
return getKieBase(KieUtils.newKieBuilder(RESOURCES));
}
private static UserTransaction getUserTransaction() {
try {
return (UserTransaction) new InitialContext().lookup("java:comp/UserTransaction");
} catch (NamingException ex) {
throw new RuntimeException("Failed to lookup transaction", ex);
}
}
@Override
protected Environment getEnvironment() {
if (emf == null) {
throw new IllegalStateException("Uninitialised EntityManagerFactory");
}
Environment env = KnowledgeBaseFactory.newEnvironment();
env.set(EnvironmentName.ENTITY_MANAGER_FACTORY, emf);
return env;
}
}