[jboss-svn-commits] JBL Code SVN: r34227 - labs/jbossrules/branches/trunk_20100722_esteban_diega/drools-compiler/src/test/java/org/drools/integrationtests.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Tue Jul 27 13:18:13 EDT 2010


Author: eaa
Date: 2010-07-27 13:18:13 -0400 (Tue, 27 Jul 2010)
New Revision: 34227

Modified:
   labs/jbossrules/branches/trunk_20100722_esteban_diega/drools-compiler/src/test/java/org/drools/integrationtests/ProcessNodeExceptionOccurredEventTest.java
Log:
JBRULES-2595: Extend ProcessEventListener to add support for low-level exceptions occurred in a process execution
	- Updated test case for subprocesses

Modified: labs/jbossrules/branches/trunk_20100722_esteban_diega/drools-compiler/src/test/java/org/drools/integrationtests/ProcessNodeExceptionOccurredEventTest.java
===================================================================
--- labs/jbossrules/branches/trunk_20100722_esteban_diega/drools-compiler/src/test/java/org/drools/integrationtests/ProcessNodeExceptionOccurredEventTest.java	2010-07-27 16:56:36 UTC (rev 34226)
+++ labs/jbossrules/branches/trunk_20100722_esteban_diega/drools-compiler/src/test/java/org/drools/integrationtests/ProcessNodeExceptionOccurredEventTest.java	2010-07-27 17:18:13 UTC (rev 34227)
@@ -1,8 +1,7 @@
 package org.drools.integrationtests;
 
+import org.drools.impl.StatefulKnowledgeSessionImpl.ProcessEventListenerWrapper;
 import org.drools.Person;
-import org.drools.runtime.process.WorkItem;
-import org.drools.runtime.process.WorkItemHandler;
 import java.util.List;
 import java.util.ArrayList;
 import org.drools.KnowledgeBase;
@@ -14,30 +13,85 @@
 import org.drools.event.process.ProcessNodeExceptionOccurredEvent;
 import org.drools.io.ResourceFactory;
 import org.drools.runtime.StatefulKnowledgeSession;
-import org.drools.runtime.process.WorkItemManager;
 import org.junit.Assert;
 import org.junit.Test;
 
+
+import org.drools.RuleBaseFactory;
+import org.drools.common.AbstractRuleBase;
+import org.drools.common.InternalWorkingMemory;
+import org.drools.reteoo.ReteooWorkingMemory;
+import org.drools.ruleflow.core.RuleFlowProcess;
+import org.drools.runtime.process.WorkItem;
+import org.drools.runtime.process.WorkItemHandler;
+import org.drools.runtime.process.WorkItemManager;
+import org.drools.WorkingMemory;
+import org.drools.spi.Action;
+import org.drools.spi.KnowledgeHelper;
+import org.drools.spi.ProcessContext;
+import org.drools.workflow.core.DroolsAction;
+import org.drools.workflow.core.Node;
+import org.drools.workflow.core.impl.ConnectionImpl;
+import org.drools.workflow.core.impl.DroolsConsequenceAction;
+import org.drools.workflow.core.node.ActionNode;
+import org.drools.workflow.core.node.EndNode;
+import org.drools.workflow.core.node.StartNode;
+import org.drools.workflow.core.node.SubProcessNode;
+
+
 import static org.junit.Assert.*;
 
 public class ProcessNodeExceptionOccurredEventTest {
 
+    /**
+     * Internal class to express an expected result of a process exception.
+     */
     private static class ExpectedResult {
 
+        /**
+         * The expected process name where the exception occurred.
+         */
+        private String processName;
+        /**
+         * The expected node name where the exception occurred.
+         */
         private String nodeName;
+        /**
+         * The expected exception name.
+         */
         private String expectedException;
 
-        public ExpectedResult(String nodeName, String expectedException) {
+        /**
+         * Creates a new ExpectedResult instance
+         * @param processName The expected process name where the exception occurred.
+         * @param nodeName The expected node name where the exception occurred.
+         * @param expectedException The expected exception name.
+         */
+        public ExpectedResult(String processName ,String nodeName, String expectedException) {
+            this.processName = processName;
             this.nodeName = nodeName;
             this.expectedException = expectedException;
         }
 
+        /**
+         * Validates this ExpectedResult instance against a ProcessNodeExceptionOccurredEvent
+         * @param event the ProcessNodeExceptionOccurredEvent triggered by the process
+         */
         public void validate(ProcessNodeExceptionOccurredEvent event) {
 
+            //Process name validation
+            if (this.processName != null) {
+                assertEquals(this.processName, event.getProcessInstance().getProcessName());
+            }
+
+            //Node name validation
             if (this.nodeName != null) {
                 assertEquals(this.nodeName, event.getNodeInstance().getNodeName());
             }
 
+            //Exception name validation. The real exception could not be the
+            //top-level exception of ProcessNodeExceptionOccurredEvent. That is
+            //why we need to navigate through the original exception.
             if (this.expectedException != null) {
                 boolean found = false;
                 Throwable t = event.getError();
@@ -56,6 +110,9 @@
         }
     }
 
+    /**
+     * A custom WorkItemHandler that will throw an exception when invoked.
+     */
     private static class FailWorkItemHandler implements WorkItemHandler {
 
         public void executeWorkItem(WorkItem workItem, WorkItemManager manager) {
@@ -66,12 +123,31 @@
         }
     }
 
-    
+    /**
+     * An internal counter to keep track on the total number of exception thrown
+     * during a process execution.
+     */
     private int exceptionCount = 0;
+
+    /**
+     * A expected result used to validate any  exception thrown
+     * during a process execution.
+     */
     private ExpectedResult expectedResult;
 
+
+    /**
+     * Custom listener that will process incoming ProcessNodeExceptionOccurredEvent
+     * events. These events are thrown when a RuntimeException occurred inside
+     * a node.
+     */
     private class CustomListener extends DefaultProcessEventListener {
 
+        /**
+         * Increments the exception counter and validates the generated event
+         * against some expected result.
+         * @param event
+         */
         @Override
         public void onNodeException(ProcessNodeExceptionOccurredEvent event) {
             exceptionCount++;
@@ -79,8 +155,15 @@
         }
     }
 
+    /**
+     * Test of ProcessNodeExceptionOccurredEvent inside an action node and inside
+     * a WorkItemHandler too.
+     * @throws InterruptedException
+     */
     @Test
     public void actionAndWorkItemExceptionTest() throws InterruptedException {
+
+        //Create a new kbase with the given flow.
         KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
         kbuilder.add(ResourceFactory.newClassPathResource("org/drools/integrationtests/ProcessNodeExceptionOccurredEventTest.rf"), ResourceType.DRF);
         if (kbuilder.hasErrors()) {
@@ -89,12 +172,12 @@
         KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
         kbase.addKnowledgePackages(kbuilder.getKnowledgePackages());
 
+        //Create a ksession and add a custom ProcessEventListener
         final StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
-
         ksession.addEventListener(new CustomListener());
 
-
-        this.expectedResult = new ExpectedResult("Some Script", "java.lang.NullPointerException");
+        //We are expecting a NPE inside "Some Script" (an action node).
+        this.expectedResult = new ExpectedResult("flow","Some Script", "java.lang.NullPointerException");
         try {
             ksession.startProcess("org.drools.test.process1");
             fail("An exception should occurr!");
@@ -104,19 +187,21 @@
         assertEquals(1, this.exceptionCount);
         this.exceptionCount = 0;
 
+        //Insert all the needed globals. Inserting a person will make that the
+        //Action node works fine.
         List<String> list = new ArrayList<String>();
-
         Person person = new Person();
         person.setName("John");
-
         ksession.setGlobal("person", person);
         ksession.setGlobal("list", list);
 
+        //Register a WorkItemHandler. This handler will throw an exception when
+        //invoked.
         ksession.getWorkItemManager().registerWorkItemHandler("Human Task", new FailWorkItemHandler());
 
-
-        this.expectedResult = new ExpectedResult("HumanTask", "java.lang.UnsupportedOperationException");
-
+        //We are expecting an UnsupportedOperationException thrown by the
+        //WorkItemHandler ("HumanTask" is its name).
+        this.expectedResult = new ExpectedResult("flow","HumanTask", "java.lang.UnsupportedOperationException");
         try {
             ksession.startProcess("org.drools.test.process1");
             fail("An exception should occurr!");
@@ -128,4 +213,103 @@
 
         ksession.dispose();
     }
+
+    /**
+     * Test for ProcessNodeExceptionOccurredEvent events thrown inside a subprocess.
+     * This test will define the main process and subprocess using apis instead
+     * of makes use of external .rf files. The result using external flow files
+     * would be the same.
+     */
+    @Test
+    public void testSubProcess() {
+
+        //Create a new Process (with name= "Process") with the following structure:
+        //Start -> SubProcess -> End
+        RuleFlowProcess process = new RuleFlowProcess();
+        process.setId("org.drools.process.process");
+        process.setName("Process");
+
+        StartNode startNode = new StartNode();
+        startNode.setName("Start");
+        startNode.setId(1);
+        process.addNode(startNode);
+        EndNode endNode = new EndNode();
+        endNode.setName("EndNode");
+        endNode.setId(2);
+        process.addNode(endNode);
+        SubProcessNode subProcessNode = new SubProcessNode();
+        subProcessNode.setName("SubProcessNode");
+        subProcessNode.setId(3);
+        subProcessNode.setProcessId("org.drools.process.subprocess");
+        process.addNode(subProcessNode);
+        new ConnectionImpl(
+            startNode, Node.CONNECTION_DEFAULT_TYPE,
+            subProcessNode, Node.CONNECTION_DEFAULT_TYPE
+        );
+        new ConnectionImpl(
+            subProcessNode, Node.CONNECTION_DEFAULT_TYPE,
+            endNode, Node.CONNECTION_DEFAULT_TYPE
+        );
+
+        //Add the process to a ruleBase.
+        AbstractRuleBase ruleBase = (AbstractRuleBase) RuleBaseFactory.newRuleBase();
+        ruleBase.addProcess(process);
+
+        //Create a new Process (with name= "SubProcess") with the following structure:
+        //Start -> Action -> End
+        //This process is used as subprocess for the later process. The action
+        //node (with name="ActionX") will throw an exception when invoked.
+        process = new RuleFlowProcess();
+        process.setId("org.drools.process.subprocess");
+        process.setName("SubProcess");
+
+        startNode = new StartNode();
+        startNode.setName("Start");
+        startNode.setId(1);
+        process.addNode(startNode);
+        endNode = new EndNode();
+        endNode.setName("EndNode");
+        endNode.setId(2);
+        process.addNode(endNode);
+        ActionNode actionNode = new ActionNode();
+        actionNode.setName("ActionX");
+        DroolsAction action = new DroolsConsequenceAction("java", null);
+        action.setMetaData("Action", new Action() {
+            public void execute(KnowledgeHelper knowledgeHelper, WorkingMemory workingMemory, ProcessContext context) throws Exception {
+            	throw new IllegalStateException("Something illegal just happened!");
+            }
+        });
+        actionNode.setAction(action);
+        process.addNode(actionNode);
+        new ConnectionImpl(
+            startNode, Node.CONNECTION_DEFAULT_TYPE,
+            actionNode, Node.CONNECTION_DEFAULT_TYPE
+        );
+        new ConnectionImpl(
+    		actionNode, Node.CONNECTION_DEFAULT_TYPE,
+            endNode, Node.CONNECTION_DEFAULT_TYPE
+        );
+
+        //Add the subprocess to ruleBase.
+        ruleBase.addProcess(process);
+
+        //The following 3 steps is the same as creating a new ksession and add
+        //a new instance of CustomListener as process listener.
+        InternalWorkingMemory workingMemory = new ReteooWorkingMemory(1, ruleBase);
+        ProcessEventListenerWrapper wrapper = new ProcessEventListenerWrapper( new CustomListener() );
+        workingMemory.addEventListener(wrapper);
+
+        //We spect the suprocess ("SubProcess") to fail inside action node ("ActionX")
+        //because of a IllegalStateException.
+        this.expectedResult = new ExpectedResult("SubProcess","ActionX", "java.lang.IllegalStateException");
+        try {
+            workingMemory.startProcess("org.drools.process.process");
+            fail("An exception should occurr!");
+        } catch (RuntimeException ex) {
+            //ok
+        }
+
+        assertEquals(1,this.exceptionCount);
+        this.exceptionCount=0;
+    }
 }



More information about the jboss-svn-commits mailing list