/* * Copyright 2015 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; import static org.jbpm.test.JBPMHelper.txStateName; import java.io.File; import java.io.FilenameFilter; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; import javax.transaction.Status; import javax.transaction.SystemException; import javax.transaction.Transaction; import junit.framework.Assert; import org.drools.core.audit.WorkingMemoryInMemoryLogger; import org.drools.core.audit.event.LogEvent; import org.drools.core.audit.event.RuleFlowNodeLogEvent; import org.h2.tools.DeleteDbFiles; import org.h2.tools.Server; import org.jbpm.process.audit.AuditLogService; import org.jbpm.process.audit.JPAAuditLogService; import org.jbpm.process.audit.NodeInstanceLog; import org.jbpm.process.instance.event.DefaultSignalManagerFactory; import org.jbpm.process.instance.impl.DefaultProcessInstanceManagerFactory; import org.jbpm.services.task.HumanTaskServiceFactory; import org.jbpm.services.task.identity.JBossUserGroupCallbackImpl; import org.jbpm.services.task.identity.MvelUserGroupCallbackImpl; import org.jbpm.workflow.instance.impl.WorkflowProcessInstanceImpl; import org.junit.After; import org.junit.Before; import org.kie.api.KieBase; import org.kie.api.definition.process.Node; import org.kie.api.io.ResourceType; import org.kie.api.runtime.KieSession; import org.kie.api.runtime.manager.RuntimeEngine; import org.kie.api.runtime.manager.RuntimeEnvironment; import org.kie.api.runtime.manager.RuntimeEnvironmentBuilder; import org.kie.api.runtime.manager.RuntimeManager; import org.kie.api.runtime.manager.RuntimeManagerFactory; import org.kie.api.runtime.process.NodeInstance; import org.kie.api.runtime.process.NodeInstanceContainer; import org.kie.api.runtime.process.ProcessInstance; import org.kie.api.runtime.process.WorkItem; import org.kie.api.runtime.process.WorkItemHandler; import org.kie.api.runtime.process.WorkItemManager; import org.kie.api.runtime.process.WorkflowProcessInstance; import org.kie.api.task.TaskService; import org.kie.internal.KnowledgeBase; import org.kie.internal.builder.KnowledgeBuilder; import org.kie.internal.builder.KnowledgeBuilderFactory; import org.kie.internal.io.ResourceFactory; import org.kie.internal.runtime.StatefulKnowledgeSession; import org.kie.internal.runtime.manager.context.EmptyContext; import org.kie.internal.task.api.InternalTaskService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import bitronix.tm.TransactionManagerServices; import bitronix.tm.resource.jdbc.PoolingDataSource; /** * This test case is deprecated. JbpmJUnitBaseTestCase shall be used instead. * @see JbpmJUnitBaseTestCase */ @Deprecated public abstract class JbpmJUnitTestCase extends AbstractBaseTest { private static final Logger testLogger = LoggerFactory.getLogger(JbpmJUnitTestCase.class); protected final static String EOL = System.getProperty("line.separator"); private boolean setupDataSource = false; private boolean sessionPersistence = false; private EntityManagerFactory emf; private PoolingDataSource ds; private H2Server server = new H2Server(); private TaskService taskService; private TestWorkItemHandler workItemHandler = new TestWorkItemHandler(); private WorkingMemoryInMemoryLogger logger; private RuntimeManager manager; private RuntimeEnvironment environment; private AuditLogService logService; // @Rule // public KnowledgeSessionCleanup ksessionCleanupRule = new KnowledgeSessionCleanup(); // protected static ThreadLocal<Set<StatefulKnowledgeSession>> knowledgeSessionSetLocal // = KnowledgeSessionCleanup.knowledgeSessionSetLocal; // @Rule // public TestName testName = new TestName(); public JbpmJUnitTestCase() { this(false); } public JbpmJUnitTestCase(boolean setupDataSource) { System.setProperty("jbpm.user.group.mapping", "classpath:/usergroups.properties"); System.setProperty("jbpm.usergroup.callback", "org.jbpm.services.task.identity.DefaultUserGroupCallbackImpl"); this.setupDataSource = setupDataSource; } public static PoolingDataSource setupPoolingDataSource() { PoolingDataSource pds = new PoolingDataSource(); pds.setUniqueName("jdbc/jbpm-ds"); pds.setClassName("bitronix.tm.resource.jdbc.lrc.LrcXADataSource"); pds.setMaxPoolSize(5); pds.setAllowLocalTransactions(true); pds.getDriverProperties().put("user", "sa"); pds.getDriverProperties().put("password", ""); pds.getDriverProperties().put("url", "jdbc:h2:tcp://localhost/~/jbpm-db;MVCC=true"); pds.getDriverProperties().put("driverClassName", "org.h2.Driver"); pds.init(); return pds; } public void setPersistence(boolean sessionPersistence) { this.sessionPersistence = sessionPersistence; } public boolean isPersistence() { return sessionPersistence; } @Before public void setUp() throws Exception { if (setupDataSource) { server.start(); ds = setupPoolingDataSource(); emf = Persistence.createEntityManagerFactory("org.jbpm.persistence.jpa"); } cleanupSingletonSessionId(); } @After public void tearDown() throws Exception { if (setupDataSource) { taskService = null; if (emf != null) { emf.close(); emf = null; } if (ds != null) { ds.close(); ds = null; } server.stop(); DeleteDbFiles.execute("~", "jbpm-db", true); // Clean up possible transactions Transaction tx = TransactionManagerServices.getTransactionManager().getCurrentTransaction(); if (tx != null) { int testTxState = tx.getStatus(); if (testTxState != Status.STATUS_NO_TRANSACTION && testTxState != Status.STATUS_ROLLEDBACK && testTxState != Status.STATUS_COMMITTED) { try { tx.rollback(); } catch (Throwable t) { // do nothing.. } Assert.fail("Transaction had status " + txStateName[testTxState] + " at the end of the test."); } } } if (manager != null) { manager.close(); } } protected KieBase createKnowledgeBase(String... process) { Map<String, ResourceType> resources = new HashMap<String, ResourceType>(); for (String p : process) { resources.put(p, ResourceType.BPMN2); } return createKnowledgeBase(resources); } protected KieBase createKnowledgeBase(Map<String, ResourceType> resources) { RuntimeEnvironmentBuilder builder = null; if (!setupDataSource){ builder = RuntimeEnvironmentBuilder.Factory.get() .newEmptyBuilder() .addConfiguration("drools.processSignalManagerFactory", DefaultSignalManagerFactory.class.getName()) .addConfiguration("drools.processInstanceManagerFactory", DefaultProcessInstanceManagerFactory.class.getName()); } else if (sessionPersistence) { builder = RuntimeEnvironmentBuilder.Factory.get() .newDefaultBuilder(); } else { builder = RuntimeEnvironmentBuilder.Factory.get() .newDefaultInMemoryBuilder(); } builder.userGroupCallback(new JBossUserGroupCallbackImpl("classpath:/usergroups.properties")); for (Map.Entry<String, ResourceType> entry : resources.entrySet()) { builder.addAsset(ResourceFactory.newClassPathResource(entry.getKey()), entry.getValue()); } environment = builder.get(); return environment.getKieBase(); } protected KnowledgeBase createKnowledgeBaseGuvnor(String... packages) throws Exception { return createKnowledgeBaseGuvnor(false, "http://localhost:8080/drools-guvnor", "admin", "admin", packages); } protected KnowledgeBase createKnowledgeBaseGuvnorAssets(String pkg, String... assets) throws Exception { return createKnowledgeBaseGuvnor(false, "http://localhost:8080/drools-guvnor", "admin", "admin", pkg, assets); } protected KnowledgeBase createKnowledgeBaseGuvnor(boolean dynamic, String url, String username, String password, String pkg, String... assets) throws Exception { KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(); String changeSet = "<change-set xmlns='http://drools.org/drools-5.0/change-set'" + EOL + " xmlns:xs='http://www.w3.org/2001/XMLSchema-instance'" + EOL + " xs:schemaLocation='http://drools.org/drools-5.0/change-set http://anonsvn.jboss.org/repos/labs/labs/jbossrules/trunk/drools-api/src/main/resources/change-set-1.0.0.xsd' >" + EOL + " <add>" + EOL; for (String a : assets) { if (a.indexOf(".bpmn") >= 0) { a = a.substring(0, a.indexOf(".bpmn")); } changeSet += " <resource source='" + url + "/rest/packages/" + pkg + "/assets/" + a + "/binary' type='BPMN2' basicAuthentication=\"enabled\" username=\"" + username + "\" password=\"" + password + "\" />" + EOL; } changeSet += " </add>" + EOL + "</change-set>"; kbuilder.add(ResourceFactory.newByteArrayResource(changeSet.getBytes()), ResourceType.CHANGE_SET); return kbuilder.newKnowledgeBase(); } protected KnowledgeBase createKnowledgeBaseGuvnor(boolean dynamic, String url, String username, String password, String... packages) throws Exception { KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder(); String changeSet = "<change-set xmlns='http://drools.org/drools-5.0/change-set'" + EOL + " xmlns:xs='http://www.w3.org/2001/XMLSchema-instance'" + EOL + " xs:schemaLocation='http://drools.org/drools-5.0/change-set http://anonsvn.jboss.org/repos/labs/labs/jbossrules/trunk/drools-api/src/main/resources/change-set-1.0.0.xsd' >" + EOL + " <add>" + EOL; for (String p : packages) { changeSet += " <resource source='" + url + "/rest/packages/" + p + "/binary' type='PKG' basicAuthentication=\"enabled\" username=\"" + username + "\" password=\"" + password + "\" />" + EOL; } changeSet += " </add>" + EOL + "</change-set>"; kbuilder.add(ResourceFactory.newByteArrayResource(changeSet.getBytes()), ResourceType.CHANGE_SET); return kbuilder.newKnowledgeBase(); } protected KieSession createKnowledgeSession() { manager = RuntimeManagerFactory.Factory.get().newSingletonRuntimeManager(environment); RuntimeEngine runtime = manager.getRuntimeEngine(EmptyContext.get()); KieSession result = runtime.getKieSession(); if (sessionPersistence) { logService = new JPAAuditLogService(environment.getEnvironment()); } else { logger = new WorkingMemoryInMemoryLogger((StatefulKnowledgeSession) result); } //knowledgeSessionSetLocal.get().add(result); return result; } protected KieSession createKnowledgeSession(String... process) { createKnowledgeBase(process); return createKnowledgeSession(); } protected KieSession restoreSession(KieSession ksession, boolean noCache) throws SystemException { if (sessionPersistence) { manager.close(); return createKnowledgeSession(); } else { return ksession; } } // public StatefulKnowledgeSession loadSession(int id, String... process) { // KnowledgeBase kbase = createKnowledgeBase(process); // // final KieSessionConfiguration config = KnowledgeBaseFactory.newKnowledgeSessionConfiguration(); // // Do NOT use the Pseudo clock yet.. // // config.setOption(ClockTypeOption.get(ClockType.PSEUDO_CLOCK.getId())); // // StatefulKnowledgeSession ksession = JPAKnowledgeService.loadStatefulKnowledgeSession(id, kbase, config, createEnvironment(emf)); // KnowledgeSessionCleanup.knowledgeSessionSetLocal.get().add(ksession); // AuditLoggerFactory.newInstance(Type.JPA, ksession, null); // // return ksession; // } public Object getVariableValue(String name, long processInstanceId, KieSession ksession) { return ((WorkflowProcessInstance) ksession.getProcessInstance(processInstanceId)).getVariable(name); } public void assertProcessInstanceCompleted(long processInstanceId, KieSession ksession) { assertNull(ksession.getProcessInstance(processInstanceId)); } public void assertProcessInstanceAborted(long processInstanceId, KieSession ksession) { assertNull(ksession.getProcessInstance(processInstanceId)); } public void assertProcessInstanceActive(long processInstanceId, KieSession ksession) { assertNotNull(ksession.getProcessInstance(processInstanceId)); } public void assertNodeActive(long processInstanceId, KieSession ksession, String... name) { List<String> names = new ArrayList<String>(); for (String n : name) { names.add(n); } ProcessInstance processInstance = ksession.getProcessInstance(processInstanceId); if (processInstance instanceof WorkflowProcessInstance) { assertNodeActive((WorkflowProcessInstance) processInstance, names); } if (!names.isEmpty()) { String s = names.get(0); for (int i = 1; i < names.size(); i++) { s += ", " + names.get(i); } fail("Node(s) not active: " + s); } } private void assertNodeActive(NodeInstanceContainer container, List<String> names) { for (NodeInstance nodeInstance : container.getNodeInstances()) { String nodeName = nodeInstance.getNodeName(); if (names.contains(nodeName)) { names.remove(nodeName); } if (nodeInstance instanceof NodeInstanceContainer) { assertNodeActive((NodeInstanceContainer) nodeInstance, names); } } } public void assertNodeTriggered(long processInstanceId, String... nodeNames) { List<String> names = new ArrayList<String>(); for (String nodeName : nodeNames) { names.add(nodeName); } if (sessionPersistence) { List<NodeInstanceLog> logs = logService.findNodeInstances(processInstanceId); if (logs != null) { for (NodeInstanceLog l : logs) { String nodeName = l.getNodeName(); if ((l.getType() == NodeInstanceLog.TYPE_ENTER || l.getType() == NodeInstanceLog.TYPE_EXIT) && names.contains(nodeName)) { names.remove(nodeName); } } } } else { for (LogEvent event : logger.getLogEvents()) { if (event instanceof RuleFlowNodeLogEvent) { String nodeName = ((RuleFlowNodeLogEvent) event).getNodeName(); if (names.contains(nodeName)) { names.remove(nodeName); } } } } if (!names.isEmpty()) { String s = names.get(0); for (int i = 1; i < names.size(); i++) { s += ", " + names.get(i); } fail("Node(s) not executed: " + s); } } protected void clearHistory() { if (sessionPersistence) { logService.clear(); } else { logger.clear(); } } public TestWorkItemHandler getTestWorkItemHandler() { return workItemHandler; } public static class TestWorkItemHandler implements WorkItemHandler { private List<WorkItem> workItems = new ArrayList<WorkItem>(); public void executeWorkItem(WorkItem workItem, WorkItemManager manager) { workItems.add(workItem); } public void abortWorkItem(WorkItem workItem, WorkItemManager manager) { } public WorkItem getWorkItem() { if (workItems.size() == 0) { return null; } if (workItems.size() == 1) { WorkItem result = workItems.get(0); this.workItems.clear(); return result; } else { throw new IllegalArgumentException("More than one work item active"); } } public List<WorkItem> getWorkItems() { List<WorkItem> result = new ArrayList<WorkItem>(workItems); workItems.clear(); return result; } } public void assertProcessVarExists(ProcessInstance process, String... processVarNames) { WorkflowProcessInstanceImpl instance = (WorkflowProcessInstanceImpl) process; List<String> names = new ArrayList<String>(); for (String nodeName : processVarNames) { names.add(nodeName); } for (String pvar : instance.getVariables().keySet()) { if (names.contains(pvar)) { names.remove(pvar); } } if (!names.isEmpty()) { String s = names.get(0); for (int i = 1; i < names.size(); i++) { s += ", " + names.get(i); } fail("Process Variable(s) do not exist: " + s); } } public void assertNodeExists(ProcessInstance process, String... nodeNames) { WorkflowProcessInstanceImpl instance = (WorkflowProcessInstanceImpl) process; List<String> names = new ArrayList<String>(); for (String nodeName : nodeNames) { names.add(nodeName); } for (Node node : instance.getNodeContainer().getNodes()) { if (names.contains(node.getName())) { names.remove(node.getName()); } } if (!names.isEmpty()) { String s = names.get(0); for (int i = 1; i < names.size(); i++) { s += ", " + names.get(i); } fail("Node(s) do not exist: " + s); } } public void assertNumOfIncommingConnections(ProcessInstance process, String nodeName, int num) { assertNodeExists(process, nodeName); WorkflowProcessInstanceImpl instance = (WorkflowProcessInstanceImpl) process; for (Node node : instance.getNodeContainer().getNodes()) { if (node.getName().equals(nodeName)) { if (node.getIncomingConnections().size() != num) { fail("Expected incomming connections: " + num + " - found " + node.getIncomingConnections().size()); } else { break; } } } } public void assertNumOfOutgoingConnections(ProcessInstance process, String nodeName, int num) { assertNodeExists(process, nodeName); WorkflowProcessInstanceImpl instance = (WorkflowProcessInstanceImpl) process; for (Node node : instance.getNodeContainer().getNodes()) { if (node.getName().equals(nodeName)) { if (node.getOutgoingConnections().size() != num) { fail("Expected outgoing connections: " + num + " - found " + node.getOutgoingConnections().size()); } else { break; } } } } public void assertVersionEquals(ProcessInstance process, String version) { WorkflowProcessInstanceImpl instance = (WorkflowProcessInstanceImpl) process; if (!instance.getWorkflowProcess().getVersion().equals(version)) { fail("Expected version: " + version + " - found " + instance.getWorkflowProcess().getVersion()); } } public void assertProcessNameEquals(ProcessInstance process, String name) { WorkflowProcessInstanceImpl instance = (WorkflowProcessInstanceImpl) process; if (!instance.getWorkflowProcess().getName().equals(name)) { fail("Expected name: " + name + " - found " + instance.getWorkflowProcess().getName()); } } public void assertPackageNameEquals(ProcessInstance process, String packageName) { WorkflowProcessInstanceImpl instance = (WorkflowProcessInstanceImpl) process; if (!instance.getWorkflowProcess().getPackageName().equals(packageName)) { fail("Expected package name: " + packageName + " - found " + instance.getWorkflowProcess().getPackageName()); } } public TaskService getTaskService() { RuntimeEngine runtime = manager.getRuntimeEngine(EmptyContext.get()); return runtime.getTaskService(); } public TaskService getService() { return (InternalTaskService) HumanTaskServiceFactory.newTaskServiceConfigurator() .userGroupCallback(new MvelUserGroupCallbackImpl(true)) .entityManagerFactory(emf) .getTaskService(); } private static class H2Server { private Server server; public synchronized void start() { if (server == null || !server.isRunning(false)) { try { DeleteDbFiles.execute("~", "jbpm-db", true); server = Server.createTcpServer(new String[0]); server.start(); } catch (SQLException e) { throw new RuntimeException("Cannot start h2 server database", e); } } } public void stop() { if (server != null) { server.stop(); server.shutdown(); DeleteDbFiles.execute("~", "jbpm-db", true); server = null; } } } public PoolingDataSource getDs() { return ds; } public EntityManagerFactory getEmf() { return emf; } public static void cleanupSingletonSessionId() { File tempDir = new File(System.getProperty("java.io.tmpdir")); if (tempDir.exists()) { String[] jbpmSerFiles = tempDir.list(new FilenameFilter() { @Override public boolean accept(File dir, String name) { return name.endsWith("-jbpmSessionId.ser"); } }); for (String file : jbpmSerFiles) { new File(tempDir, file).delete(); } } } }