/* * 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. * 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.jbpm.kie.services.impl.admin; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.kie.scanner.MavenRepository.getMavenRepository; import java.io.File; import java.io.FileOutputStream; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import org.drools.compiler.kie.builder.impl.InternalKieModule; import org.jbpm.kie.services.impl.KModuleDeploymentUnit; import org.jbpm.kie.services.test.KModuleDeploymentServiceTest; import org.jbpm.kie.test.util.AbstractKieServicesBaseTest; import org.jbpm.kie.test.util.CountDownListenerFactory; import org.jbpm.services.api.ProcessInstanceNotFoundException; import org.jbpm.services.api.admin.ProcessInstanceAdminService; import org.jbpm.services.api.admin.ProcessNode; import org.jbpm.services.api.admin.TimerInstance; import org.jbpm.services.api.model.DeploymentUnit; import org.jbpm.services.api.model.NodeInstanceDesc; import org.jbpm.services.api.model.ProcessInstanceDesc; import org.jbpm.shared.services.impl.TransactionalCommandService; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.kie.api.KieServices; import org.kie.api.builder.ReleaseId; import org.kie.api.runtime.process.ProcessInstance; import org.kie.api.runtime.query.QueryContext; import org.kie.api.task.model.TaskSummary; import org.kie.internal.query.QueryFilter; import org.kie.internal.runtime.conf.ObjectModel; import org.kie.internal.runtime.error.ExecutionError; import org.kie.scanner.MavenRepository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ProcessInstanceAdminServiceImplTest extends AbstractKieServicesBaseTest { private static final Logger logger = LoggerFactory.getLogger(KModuleDeploymentServiceTest.class); protected static final String ADMIN_ARTIFACT_ID = "test-admin"; protected static final String ADMIN_GROUP_ID = "org.jbpm.test"; protected static final String ADMIN_VERSION_V1 = "1.0.0"; private List<DeploymentUnit> units = new ArrayList<DeploymentUnit>(); private KModuleDeploymentUnit deploymentUnit; private Long processInstanceId = null; protected ProcessInstanceAdminService processAdminService; @Before public void prepare() { configureServices(); logger.debug("Preparing kjar"); KieServices ks = KieServices.Factory.get(); // version 1 of kjar ReleaseId releaseId = ks.newReleaseId(ADMIN_GROUP_ID, ADMIN_ARTIFACT_ID, ADMIN_VERSION_V1); List<String> processes = new ArrayList<String>(); processes.add("repo/processes/general/humanTask.bpmn"); processes.add("repo/processes/general/BPMN2-IntermediateCatchEventTimerDuration.bpmn2"); processes.add("repo/processes/errors/BPMN2-BrokenScriptTask.bpmn2"); processes.add("repo/processes/errors/BPMN2-UserTaskWithRollback.bpmn2"); InternalKieModule kJar1 = createKieJar(ks, releaseId, processes); File pom = new File("target/admin", "pom.xml"); pom.getParentFile().mkdir(); try { FileOutputStream fs = new FileOutputStream(pom); fs.write(getPom(releaseId).getBytes()); fs.close(); } catch (Exception e) { } MavenRepository repository = getMavenRepository(); repository.installArtifact(releaseId, kJar1, pom); processAdminService = new ProcessInstanceAdminServiceImpl(); ((ProcessInstanceAdminServiceImpl) processAdminService).setProcessService(processService); ((ProcessInstanceAdminServiceImpl) processAdminService).setRuntimeDataService(runtimeDataService); ((ProcessInstanceAdminServiceImpl) processAdminService).setCommandService(new TransactionalCommandService(emf)); ((ProcessInstanceAdminServiceImpl) processAdminService).setIdentityProvider(identityProvider); // now let's deploy to runtime both kjars deploymentUnit = new KModuleDeploymentUnit(ADMIN_GROUP_ID, ADMIN_ARTIFACT_ID, ADMIN_VERSION_V1); deploymentService.deploy(deploymentUnit); units.add(deploymentUnit); } @After public void cleanup() { cleanupSingletonSessionId(); if (processInstanceId != null) { try { // let's abort process instance to leave the system in clear state processService.abortProcessInstance(processInstanceId); ProcessInstance pi = processService.getProcessInstance(processInstanceId); assertNull(pi); } catch (ProcessInstanceNotFoundException e) { // ignore it as it might already be completed/aborted } } if (units != null && !units.isEmpty()) { for (DeploymentUnit unit : units) { try { deploymentService.undeploy(unit); } catch (Exception e) { // do nothing in case of some failed tests to avoid next test to fail as well } } units.clear(); } close(); CountDownListenerFactory.clear(); } public void setProcessAdminService(ProcessInstanceAdminService processAdminService) { this.processAdminService = processAdminService; } @Test public void testGetNodes() { processInstanceId = processService.startProcess(deploymentUnit.getIdentifier(), "org.jbpm.writedocument"); assertNotNull(processInstanceId); Collection<ProcessNode> processNodes = processAdminService.getProcessNodes(processInstanceId); assertNotNull(processNodes); assertEquals(8, processNodes.size()); Map<String, String> mappedNodes = processNodes.stream().collect(Collectors.toMap(ProcessNode::getNodeName, ProcessNode::getNodeType)); assertEquals("StartNode", mappedNodes.get("Start")); assertEquals("HumanTaskNode", mappedNodes.get("Write a Document")); assertEquals("Split", mappedNodes.get("Review and Translate")); assertEquals("HumanTaskNode", mappedNodes.get("Translate Document")); assertEquals("HumanTaskNode", mappedNodes.get("Review Document")); assertEquals("Join", mappedNodes.get("Reviewed and Translated")); assertEquals("ActionNode", mappedNodes.get("Report")); assertEquals("EndNode", mappedNodes.get("End")); } @Test public void testCancelAndTriger() { processInstanceId = processService.startProcess(deploymentUnit.getIdentifier(), "org.jbpm.writedocument"); assertNotNull(processInstanceId); Collection<NodeInstanceDesc> activeNodes = processAdminService.getActiveNodeInstances(processInstanceId); assertNotNull(activeNodes); assertEquals(1, activeNodes.size()); NodeInstanceDesc active = activeNodes.iterator().next(); assertEquals("Write a Document", active.getName()); List<TaskSummary> tasks = runtimeDataService.getTasksAssignedAsPotentialOwner("salaboy", new QueryFilter()); assertEquals(1, tasks.size()); processAdminService.cancelNodeInstance(processInstanceId, active.getId()); activeNodes = processAdminService.getActiveNodeInstances(processInstanceId); assertNotNull(activeNodes); assertEquals(0, activeNodes.size()); tasks = runtimeDataService.getTasksAssignedAsPotentialOwner("salaboy", new QueryFilter()); assertEquals(0, tasks.size()); Collection<ProcessNode> processNodes = processAdminService.getProcessNodes(processInstanceId); ProcessNode writeDocNode = processNodes.stream().filter(pn -> pn.getNodeName().equals(active.getName())).findFirst().orElse(null); processAdminService.triggerNode(processInstanceId, writeDocNode.getNodeId()); activeNodes = processAdminService.getActiveNodeInstances(processInstanceId); assertNotNull(activeNodes); assertEquals(1, activeNodes.size()); tasks = runtimeDataService.getTasksAssignedAsPotentialOwner("salaboy", new QueryFilter()); assertEquals(1, tasks.size()); } @Test public void testRetriggerNodeInstance() { processInstanceId = processService.startProcess(deploymentUnit.getIdentifier(), "org.jbpm.writedocument"); assertNotNull(processInstanceId); Collection<NodeInstanceDesc> activeNodes = processAdminService.getActiveNodeInstances(processInstanceId); assertNotNull(activeNodes); assertEquals(1, activeNodes.size()); NodeInstanceDesc active = activeNodes.iterator().next(); assertEquals("Write a Document", active.getName()); List<TaskSummary> tasks = runtimeDataService.getTasksAssignedAsPotentialOwner("salaboy", new QueryFilter()); assertEquals(1, tasks.size()); TaskSummary task = tasks.get(0); processAdminService.retriggerNodeInstance(processInstanceId, active.getId()); activeNodes = processAdminService.getActiveNodeInstances(processInstanceId); assertNotNull(activeNodes); assertEquals(1, activeNodes.size()); NodeInstanceDesc activeRetriggered = activeNodes.iterator().next(); assertFalse(active.getId().longValue() == activeRetriggered.getId().longValue()); tasks = runtimeDataService.getTasksAssignedAsPotentialOwner("salaboy", new QueryFilter()); assertEquals(1, tasks.size()); TaskSummary taskRetriggered = tasks.get(0); assertFalse(task.getId().longValue() == taskRetriggered.getId().longValue()); } @Test public void testCancelAndTrigerAnotherNode() { processInstanceId = processService.startProcess(deploymentUnit.getIdentifier(), "org.jbpm.writedocument"); assertNotNull(processInstanceId); Collection<NodeInstanceDesc> activeNodes = processAdminService.getActiveNodeInstances(processInstanceId); assertNotNull(activeNodes); assertEquals(1, activeNodes.size()); NodeInstanceDesc active = activeNodes.iterator().next(); assertEquals("Write a Document", active.getName()); List<TaskSummary> tasks = runtimeDataService.getTasksAssignedAsPotentialOwner("salaboy", new QueryFilter()); assertEquals(1, tasks.size()); processAdminService.cancelNodeInstance(processInstanceId, active.getId()); activeNodes = processAdminService.getActiveNodeInstances(processInstanceId); assertNotNull(activeNodes); assertEquals(0, activeNodes.size()); tasks = runtimeDataService.getTasksAssignedAsPotentialOwner("salaboy", new QueryFilter()); assertEquals(0, tasks.size()); Collection<ProcessNode> processNodes = processAdminService.getProcessNodes(processInstanceId); ProcessNode writeDocNode = processNodes.stream().filter(pn -> pn.getNodeName().equals("Report")).findFirst().orElse(null); processAdminService.triggerNode(processInstanceId, writeDocNode.getNodeId()); activeNodes = processAdminService.getActiveNodeInstances(processInstanceId); assertNotNull(activeNodes); assertEquals(0, activeNodes.size()); tasks = runtimeDataService.getTasksAssignedAsPotentialOwner("salaboy", new QueryFilter()); assertEquals(0, tasks.size()); ProcessInstanceDesc pi = runtimeDataService.getProcessInstanceById(processInstanceId); assertEquals(ProcessInstance.STATE_COMPLETED, pi.getState().intValue()); processInstanceId = null; } @Test public void testTrigerLastActionNode() { processInstanceId = processService.startProcess(deploymentUnit.getIdentifier(), "org.jbpm.writedocument"); assertNotNull(processInstanceId); Collection<NodeInstanceDesc> activeNodes = processAdminService.getActiveNodeInstances(processInstanceId); assertNotNull(activeNodes); assertEquals(1, activeNodes.size()); NodeInstanceDesc active = activeNodes.iterator().next(); assertEquals("Write a Document", active.getName()); List<TaskSummary> tasks = runtimeDataService.getTasksAssignedAsPotentialOwner("salaboy", new QueryFilter()); assertEquals(1, tasks.size()); Collection<ProcessNode> processNodes = processAdminService.getProcessNodes(processInstanceId); ProcessNode writeDocNode = processNodes.stream().filter(pn -> pn.getNodeName().equals("Report")).findFirst().orElse(null); processAdminService.triggerNode(processInstanceId, writeDocNode.getNodeId()); activeNodes = processAdminService.getActiveNodeInstances(processInstanceId); assertNotNull(activeNodes); assertEquals(0, activeNodes.size()); tasks = runtimeDataService.getTasksAssignedAsPotentialOwner("salaboy", new QueryFilter()); assertEquals(0, tasks.size()); ProcessInstanceDesc pi = runtimeDataService.getProcessInstanceById(processInstanceId); assertEquals(ProcessInstance.STATE_COMPLETED, pi.getState().intValue()); processInstanceId = null; } @Test(timeout=10000) public void testUpdateTimer() throws Exception { processInstanceId = processService.startProcess(deploymentUnit.getIdentifier(), "IntermediateCatchEvent"); assertNotNull(processInstanceId); long scheduleTime = System.currentTimeMillis(); Collection<NodeInstanceDesc> activeNodes = processAdminService.getActiveNodeInstances(processInstanceId); assertNotNull(activeNodes); assertEquals(1, activeNodes.size()); NodeInstanceDesc active = activeNodes.iterator().next(); assertEquals("timer", active.getName()); Collection<TimerInstance> timers = processAdminService.getTimerInstances(processInstanceId); assertNotNull(timers); assertEquals(1, timers.size()); TimerInstance timer = timers.iterator().next(); assertNotNull(timer.getActivationTime()); assertNotNull(timer.getDelay()); assertNotNull(timer.getNextFireTime()); assertNotNull(timer.getProcessInstanceId()); assertNotNull(timer.getSessionId()); assertNotNull(timer.getTimerId()); assertNotNull(timer.getTimerName()); // thread sleep to test the different in the time timer spent after upgrade // not to wait for any job to be done Thread.sleep(1000); processAdminService.updateTimer(processInstanceId, timer.getTimerId(), 3, 0, 0); CountDownListenerFactory.getExisting("processAdminService").waitTillCompleted(); long fireTime = System.currentTimeMillis(); long expirationTime = fireTime - scheduleTime; //since the update of timer was including time already spent (thread sleep above) then it must wait less than 4 secs assertTrue(expirationTime < 4000); ProcessInstanceDesc pi = runtimeDataService.getProcessInstanceById(processInstanceId); assertEquals(ProcessInstance.STATE_COMPLETED, pi.getState().intValue()); processInstanceId = null; } @Test(timeout=10000) public void testUpdateTimerRelative() throws Exception { processInstanceId = processService.startProcess(deploymentUnit.getIdentifier(), "IntermediateCatchEvent"); assertNotNull(processInstanceId); long scheduleTime = System.currentTimeMillis(); Collection<NodeInstanceDesc> activeNodes = processAdminService.getActiveNodeInstances(processInstanceId); assertNotNull(activeNodes); assertEquals(1, activeNodes.size()); NodeInstanceDesc active = activeNodes.iterator().next(); assertEquals("timer", active.getName()); Collection<TimerInstance> timers = processAdminService.getTimerInstances(processInstanceId); assertNotNull(timers); assertEquals(1, timers.size()); TimerInstance timer = timers.iterator().next(); assertNotNull(timer.getActivationTime()); assertNotNull(timer.getDelay()); assertNotNull(timer.getNextFireTime()); assertNotNull(timer.getProcessInstanceId()); assertNotNull(timer.getSessionId()); assertNotNull(timer.getTimerId()); assertNotNull(timer.getTimerName()); // thread sleep to test the different in the time timer spent after upgrade // not to wait for any job to be done Thread.sleep(1000); processAdminService.updateTimerRelative(processInstanceId, timer.getTimerId(), 3, 0, 0); CountDownListenerFactory.getExisting("processAdminService").waitTillCompleted(); long fireTime = System.currentTimeMillis(); //since the update of timer was relative (to current time) then it must wait at least 3 secs long expirationTime = fireTime - scheduleTime; assertTrue(expirationTime > 3000); ProcessInstanceDesc pi = runtimeDataService.getProcessInstanceById(processInstanceId); assertEquals(ProcessInstance.STATE_COMPLETED, pi.getState().intValue()); processInstanceId = null; } @Test public void testErrorHandlingOnScriptTask() { try { processService.startProcess(deploymentUnit.getIdentifier(), "BrokenScriptTask"); } catch (Exception e) { // expected as this is broken script process } List<ExecutionError> errors = processAdminService.getErrors(true, new QueryContext()); assertNotNull(errors); assertEquals(1, errors.size()); } /* * Helper methods */ @Override protected List<ObjectModel> getProcessListeners() { List<ObjectModel> listeners = super.getProcessListeners(); listeners.add(new ObjectModel("mvel", "org.jbpm.kie.test.util.CountDownListenerFactory.get(\"processAdminService\", \"timer\", 1)")); return listeners; } protected boolean createDescriptor() { return true; } }