/*
* 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.functional.timer;
import static org.jbpm.test.JBPMHelper.processStateName;
import java.util.HashMap;
import java.util.Map;
import org.drools.core.process.instance.WorkItemHandler;
import org.jbpm.test.JbpmTestCase;
import org.junit.Before;
import org.junit.Test;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.manager.RuntimeEngine;
import org.kie.api.runtime.process.ProcessInstance;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* See JBPM-3170/JBPM-3391
*/
public class InMemoryTimerPersistenceTest extends JbpmTestCase {
// General setup
private static final Logger logger = LoggerFactory.getLogger(InMemoryTimerPersistenceTest.class);
// Test processses
private final static String PROCESS_FILE_NAME = "org/jbpm/test/functional/timer/boundaryTimerProcess.bpmn";
private final static String PROCESS_NAME = "BoundaryTimerEventProcess";
private final static String WORK_ITEM_HANLDER_TASK = "Human Task";
private final static String TIMER_FIRED_PROP = "timerFired";
private final static String TIMER_FIRED_TIME_PROP = "afterTimerTime";
public InMemoryTimerPersistenceTest() {
super(true, false);
}
@Before
public void setup() {
System.clearProperty(TIMER_FIRED_PROP);
System.clearProperty(TIMER_FIRED_TIME_PROP);
}
@Test
public void boundaryEventTimerAndCompleteHumanTaskWithoutPersistence() throws InterruptedException {
createRuntimeManager(PROCESS_FILE_NAME);
RuntimeEngine runtimeEngine = getRuntimeEngine();
KieSession ksession = runtimeEngine.getKieSession();
// Do stuff
HumanTaskMockHandler humanTaskMockHandler = new HumanTaskMockHandler();
ProcessInstance process = registerHTHandlerAndStartProcess(ksession, humanTaskMockHandler);
sleepAndVerifyTimerRuns(process.getState());
completeWork(ksession, humanTaskMockHandler);
// The process reaches the end node
int processState = process.getState();
assertEquals("Expected process state to be " + processStateName[ProcessInstance.STATE_COMPLETED],
ProcessInstance.STATE_COMPLETED, processState);
}
private ProcessInstance registerHTHandlerAndStartProcess(KieSession ksession, HumanTaskMockHandler humanTaskMockHandler) {
// Register Human Task Handler
ksession.getWorkItemManager().registerWorkItemHandler(WORK_ITEM_HANLDER_TASK, humanTaskMockHandler);
// Start the process
ProcessInstance process = ksession.startProcess(PROCESS_NAME);
long processId = process.getId();
assertTrue("process id not saved", processId > 0);
// The process is in the Human Task waiting for its completion
int processState = process.getState();
assertEquals("Expected process state to be " + processStateName[ProcessInstance.STATE_ACTIVE] + " not "
+ processStateName[processState], ProcessInstance.STATE_ACTIVE, processState);
return process;
}
private void completeWork(KieSession ksession, HumanTaskMockHandler humanTaskMockHandler) {
assertTrue("The work item task handler does not have a work item!", humanTaskMockHandler.workItem != null);
long workItemId = humanTaskMockHandler.workItem.getId();
assertTrue("work item id not saved", workItemId > 0);
// The Human Task is completed
Map<String, Object> results = new HashMap<String, Object>();
try {
ksession.getWorkItemManager().completeWorkItem(workItemId, results);
} catch (Exception e) {
logger.warn("Work item could not be completed!");
e.printStackTrace();
fail(e.getClass().getSimpleName() + " thrown when completing work item: " + e.getMessage());
}
}
private void sleepAndVerifyTimerRuns(int processState) throws InterruptedException {
// wait 3 seconds to see if the boss is notified
if (processState == ProcessInstance.STATE_ACTIVE) {
int sleep = 2000;
logger.debug("Sleeping {} seconds", sleep / 1000);
Thread.sleep(sleep);
logger.debug("Awake!");
}
long afterSleepTime = System.currentTimeMillis();
assertTrue("The timer has not fired!", timerHasFired());
assertTrue("The timer did not fire on time!", afterSleepTime > timerFiredTime() );
int timerFiredCount = timerFiredCount();
assertTrue("The timer only fired " + timerFiredCount + " times.", timerFiredCount >= 1 );
}
private boolean timerHasFired() {
String hasFired = System.getProperty(TIMER_FIRED_PROP);
if( hasFired != null ) {
return true;
}
return false;
}
private int timerFiredCount() {
String timerFiredCount = System.getProperty(TIMER_FIRED_PROP);
if( timerFiredCount == null ) {
return 0;
}
return Integer.parseInt(timerFiredCount);
}
private long timerFiredTime() {
String timerFiredCount = System.getProperty(TIMER_FIRED_TIME_PROP);
if( timerFiredCount == null ) {
return 0;
}
return Long.parseLong(timerFiredCount);
}
private static class HumanTaskMockHandler implements WorkItemHandler {
private org.kie.api.runtime.process.WorkItemManager workItemManager;
private org.kie.api.runtime.process.WorkItem workItem;
public void executeWorkItem(org.kie.api.runtime.process.WorkItem workItem, org.kie.api.runtime.process.WorkItemManager manager) {
this.workItem = workItem;
this.workItemManager = manager;
logger.debug("Work completed!");
}
public void abortWorkItem(org.kie.api.runtime.process.WorkItem workItem, org.kie.api.runtime.process.WorkItemManager manager) {
this.workItemManager.abortWorkItem(workItem.getId());
logger.debug("Work aborted.");
}
}
}