/* * Copyright (c) NASK, NCSC * * This file is part of HoneySpider Network 2.1. * * This is a free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package pl.nask.hsn2.workflow.engine; import java.util.Arrays; import java.util.HashSet; import java.util.Properties; import org.testng.Assert; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import pl.nask.hsn2.bus.api.BusManager; import pl.nask.hsn2.bus.api.Message; import pl.nask.hsn2.bus.connector.objectstore.ObjectStoreConnector; import pl.nask.hsn2.bus.connector.objectstore.ObjectStoreConnectorException; import pl.nask.hsn2.bus.connector.objectstore.StubObjectStoreConnector; import pl.nask.hsn2.bus.connector.process.ProcessConnector; import pl.nask.hsn2.bus.connector.process.ProcessConnectorException; import pl.nask.hsn2.bus.connector.process.StubProcessConnector; import pl.nask.hsn2.bus.operations.JobStatus; import pl.nask.hsn2.bus.operations.ObjectData; import pl.nask.hsn2.framework.bus.FrameworkBus; import pl.nask.hsn2.framework.suppressor.SingleThreadTasksSuppressor; import pl.nask.hsn2.framework.workflow.engine.WorkflowDescriptor; import pl.nask.hsn2.framework.workflow.engine.WorkflowEngineException; import pl.nask.hsn2.framework.workflow.hwl.Output; import pl.nask.hsn2.framework.workflow.hwl.ProcessDefinition; import pl.nask.hsn2.framework.workflow.hwl.Service; import pl.nask.hsn2.framework.workflow.hwl.Workflow; import pl.nask.hsn2.framework.workflow.job.WorkflowJob; import pl.nask.hsn2.utils.AtomicLongIdGenerator; public class WorkflowEngineTest { ActivitiWorkflowEngine engine; ActivitiWorkflowDefinitionManager definitionManager; MyBus bus = new MyBus(); @BeforeClass public void prepareWorkflows() throws WorkflowEngineException { BusManager.setBus(bus); definitionManager = new ActivitiWorkflowDefinitionManager(); definitionManager.registerWorkflow( definitionManager.createDescritor("twoServices", "noFile", twoServicesWorkflow())); definitionManager.registerWorkflow( definitionManager.createDescritor("withSubProcess", "noFile", oneServiceWithSubprocess())); definitionManager.registerWorkflow( definitionManager.createDescritor("withEmptySubprocess", "noFile", oneServiceWithEmptySubprocess())); definitionManager.deploy("twoServices"); definitionManager.deploy("withSubProcess"); definitionManager.deploy("withEmptySubprocess"); } private Workflow oneServiceWithSubprocess() { Workflow w = new Workflow(); ProcessDefinition process = new ProcessDefinition("main"); Service service = new Service("service"); service.addOutput(new Output("subprocess")); process.addExecutionPoint(service); w.addProcess(process); ProcessDefinition subprocess = new ProcessDefinition("subprocess"); subprocess.addExecutionPoint(new Service("subservice")); w.addProcess(subprocess); return w; } private Workflow oneServiceWithEmptySubprocess() { Workflow w = new Workflow(); ProcessDefinition process = new ProcessDefinition("main"); Service service = new Service("service"); service.addOutput(new Output("subprocess")); process.addExecutionPoint(service); w.addProcess(process); ProcessDefinition subprocess = new ProcessDefinition("subprocess"); w.addProcess(subprocess); return w; } private Workflow twoServicesWorkflow() { Workflow w = new Workflow(); ProcessDefinition process = new ProcessDefinition("main"); process.addExecutionPoint(new Service("service")); process.addExecutionPoint(new Service("service2")); w.addProcess(process ); return w; } @BeforeMethod public void prepareEngine() { engine = new ActivitiWorkflowEngine(new AtomicLongIdGenerator(), new SingleThreadTasksSuppressor(true), 1); } @Test public void testStartJob() throws Exception { WorkflowDescriptor descriptor = definitionManager.get("twoServices"); long jobId = engine.startJob(descriptor); WorkflowJob job = engine.getJob(jobId); Assert.assertEquals(JobStatus.PROCESSING, job.getStatus()); Assert.assertFalse(job.isEnded()); Assert.assertEquals(job.getActiveStepName(), "start"); } @Test public void testAcceptTask() throws Exception { WorkflowDescriptor descriptor = definitionManager.get("twoServices"); long jobId = engine.startJob(descriptor); WorkflowJob job = engine.getJob(jobId); job.resume(); Assert.assertEquals(job.getActiveStepName(), "service(service)"); int taskId = bus.getLastTaskId(); //int taskId = getLastTaskId(); job.markTaskAsAccepted(taskId); // service name is still the same Assert.assertEquals(job.getActiveStepName(), "service(service)"); // same as the taskId //Assert.assertEquals(taskId, getLastTaskId()); Assert.assertEquals(taskId, bus.getLastTaskId()); } @Test public void testCompleteTask() throws Exception { WorkflowDescriptor descriptor = definitionManager.get("twoServices"); long jobId = engine.startJob(descriptor); WorkflowJob job = engine.getJob(jobId); job.resume(); //int taskId = getLastTaskId(); int taskId = bus.getLastTaskId(); job.markTaskAsCompleted(taskId, null); Assert.assertEquals(job.getActiveStepName(), "service(service2)"); //Assert.assertFalse(taskId == getLastTaskId()); Assert.assertFalse(taskId == bus.getLastTaskId()); } @Test public void testResumeMainProcess() throws Exception { WorkflowDescriptor descriptor = definitionManager.get("twoServices"); long jobId = engine.startJob(descriptor); WorkflowJob job = engine.getJob(jobId); Assert.assertEquals("start", job.getActiveStepName()); job.resume(); Assert.assertEquals(job.getActiveStepName(), "service(service)"); } @Test public void testCompleteSubprocessTask() throws Exception { WorkflowDescriptor descriptor = definitionManager.get("withSubProcess"); long jobId = engine.startJob(descriptor); WorkflowJob job = engine.getJob(jobId); job.resume(); //int taskId = getLastTaskId(); int taskId = bus.getLastTaskId(); job.markTaskAsCompleted(taskId, new HashSet<Long>(Arrays.asList(1L))); // the main process should stop on the wait state Assert.assertFalse(job.isEnded()); int subtaskId = bus.getLastTaskId(); //int subtaskId = getLastTaskId(); job.markTaskAsCompleted(subtaskId, null); // this should trigger 'wait' in the main to end the process Assert.assertTrue(job.isEnded()); } public static class MyBus implements FrameworkBus { private int lastTaskId = -1; private ObjectStoreConnector objectStoreConnector = new StubObjectStoreConnector(){ @Override public Long sendObjectStoreData( long jobId, ObjectData dataList) throws ObjectStoreConnectorException { return 1L; } }; public void sendHighPriorityMessage(Message message) {} public ObjectStoreConnector getObjectStoreConnector() { return this.objectStoreConnector; } public ProcessConnector getProcessConnector() { return new StubProcessConnector() { @Override public void sendTaskRequest(String serviceName, String serviceId, long jobId, int taskId, long objectDataId, Properties parameters) throws ProcessConnectorException { lastTaskId = taskId; } }; } @Override public void start() { } @Override public void stop() { } @Override public boolean isRunning() { return true; } @Override public void jobStarted(long jobId) { } @Override public void jobFinished(long jobId, JobStatus status) { } int getLastTaskId() { try { Thread.sleep(100); } catch (InterruptedException e) { // nothing to do } return lastTaskId; } @Override public void jobFinishedReminder(long jobId, JobStatus status, int offendingTask) { } @Override public void releaseResources() { throw new IllegalStateException("Not implemented!."); } } }