Package org.drools.reteoo.common

Source Code of org.drools.reteoo.common.AgendaTest

/*
* Copyright 2005 JBoss Inc
*
* 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.drools.reteoo.common;

import org.drools.core.RuleBaseConfiguration;
import org.drools.core.RuleBaseFactory;
import org.drools.core.WorkingMemory;
import org.drools.core.base.SalienceInteger;
import org.drools.core.common.AbstractWorkingMemory;
import org.drools.core.common.AgendaGroupQueueImpl;
import org.drools.core.common.AgendaItem;
import org.drools.core.common.DefaultFactHandle;
import org.drools.core.common.InternalAgenda;
import org.drools.core.common.InternalAgendaGroup;
import org.drools.core.common.InternalRuleBase;
import org.drools.core.common.InternalRuleFlowGroup;
import org.drools.core.common.InternalWorkingMemory;
import org.drools.core.common.PropagationContextFactory;
import org.drools.core.event.ActivationCancelledEvent;
import org.drools.core.event.DefaultAgendaEventListener;
import org.drools.core.reteoo.MockTupleSource;
import org.drools.core.reteoo.ReteooBuilder.IdGenerator;
import org.drools.core.reteoo.ReteooRuleBase;
import org.drools.core.reteoo.RuleTerminalNode;
import org.drools.core.reteoo.RuleTerminalNodeLeftTuple;
import org.drools.core.reteoo.builder.BuildContext;
import org.drools.core.rule.Rule;
import org.drools.core.spi.Activation;
import org.drools.core.spi.ActivationGroup;
import org.drools.core.spi.AgendaFilter;
import org.drools.core.spi.AgendaGroup;
import org.drools.core.spi.Consequence;
import org.drools.core.spi.ConsequenceException;
import org.drools.core.spi.KnowledgeHelper;
import org.drools.core.spi.PropagationContext;
import org.drools.core.spi.RuleFlowGroup;
import org.drools.core.test.model.Cheese;
import org.drools.core.test.model.DroolsTestCase;
import org.drools.core.time.impl.DurationTimer;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.kie.api.event.rule.MatchCancelledCause;
import org.kie.api.runtime.rule.Match;
import org.kie.internal.event.rule.ActivationUnMatchListener;

import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

@Ignore
public class AgendaTest extends DroolsTestCase {
    private InternalRuleBase          ruleBase;
    private BuildContext              buildContext;
    private PropagationContextFactory pctxFactory;

    @Before
    public void setUp() throws Exception {
        RuleBaseConfiguration config = new RuleBaseConfiguration();
        config.setPhreakEnabled(false);
        ruleBase = (InternalRuleBase) RuleBaseFactory.newRuleBase(config);
        buildContext = new BuildContext(ruleBase,
                                        ((ReteooRuleBase) ruleBase).getReteooBuilder().getIdGenerator());
        pctxFactory = ruleBase.getConfiguration().getComponentFactory().getPropagationContextFactory();
    }

    @Test
    public void testClearAgenda() {
        final AbstractWorkingMemory workingMemory = (AbstractWorkingMemory) ruleBase.newStatefulSession();

        final InternalAgenda agenda = (InternalAgenda) workingMemory.getAgenda();

        final Rule rule1 = new Rule("test-rule1");
        final Rule rule2 = new Rule("test-rule2");

        final RuleTerminalNode node1 = new RuleTerminalNode(3,
                                                            new MockTupleSource(2),
                                                            rule1,
                                                            rule1.getLhs(),
                                                            0,
                                                            buildContext);

        final RuleTerminalNode node2 = new RuleTerminalNode(5,
                                                            new MockTupleSource(4),
                                                            rule2,
                                                            rule2.getLhs(),
                                                            0,
                                                            buildContext);

        final RuleTerminalNodeLeftTuple tuple1 = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(1, "cheese"), node1, true);
        final RuleTerminalNodeLeftTuple tuple2 = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(2, "cheese"), node2, true);

        final PropagationContext context1 = pctxFactory.createPropagationContext(0,
                                                                                 PropagationContext.INSERTION,
                                                                                 rule1,
                                                                                 null,
                                                                                 new DefaultFactHandle());

        // Add consequence. Notice here the context here for the add to ageyunda
        // is itself
        rule1.setConsequence(new org.drools.core.spi.Consequence() {
            private static final long serialVersionUID = 510l;

            public void evaluate(final KnowledgeHelper knowledgeHelper,
                                 final WorkingMemory workingMemory) {
                // do nothing
            }

            public void readExternal(ObjectInput in) throws IOException,
                    ClassNotFoundException {

            }

            public void writeExternal(ObjectOutput out) throws IOException {

            }

            public String getName() {
                return "default";
            }
        });

        // Add consequence. Notice here the context here for the add to ageyunda
        // is itself
        rule2.setConsequence(new org.drools.core.spi.Consequence() {
            private static final long serialVersionUID = 510l;

            public void evaluate(final KnowledgeHelper knowledgeHelper,
                                 final WorkingMemory workingMemory) {
                // do nothing
            }

            public void readExternal(ObjectInput in) throws IOException,
                    ClassNotFoundException {

            }

            public void writeExternal(ObjectOutput out) throws IOException {

            }

            public String getName() {
                return "default";
            }
        });

        assertEquals(0,
                     agenda.getFocus().size());

        rule1.setNoLoop(false);
        rule2.setTimer(new DurationTimer(5000));

        node1.assertLeftTuple(tuple1,
                              context1,
                              workingMemory);

        node2.assertLeftTuple(tuple2,
                              context1,
                              workingMemory);

        agenda.unstageActivations();

        // make sure we have an activation in the current focus
        assertEquals(1,
                     agenda.getFocus().size());

        assertEquals(1,
                     agenda.getScheduledActivations().length);

        agenda.clearAndCancel();

        assertEquals(0,
                     agenda.getFocus().size());

        assertEquals(0,
                     agenda.getScheduledActivations().length);
    }

    @Test
    public void testActivationUnMatchListener() {
        final AbstractWorkingMemory workingMemory = (AbstractWorkingMemory) ruleBase.newStatefulSession();

        final InternalAgenda agenda = (InternalAgenda) workingMemory.getAgenda();

        final Rule rule1 = new Rule("test-rule1");

        final RuleTerminalNode node1 = new RuleTerminalNode(3,
                                                            new MockTupleSource(2),
                                                            rule1,
                                                            rule1.getLhs(),
                                                            0,
                                                            buildContext);

        Cheese cheese = new Cheese();
        cheese.setPrice(50);
        final RuleTerminalNodeLeftTuple tuple = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(1, cheese), node1, true);

        final PropagationContext context1 = pctxFactory.createPropagationContext(0,
                                                                                 PropagationContext.INSERTION,
                                                                                 rule1,
                                                                                 null,
                                                                                 new DefaultFactHandle());

        // Add consequence. Notice here the context here for the add to ageyunda
        // is itself
        rule1.setConsequence(new org.drools.core.spi.Consequence() {
            private static final long serialVersionUID = 510l;

            public void evaluate(final KnowledgeHelper knowledgeHelper,
                                 final WorkingMemory workingMemory) {
                AgendaItem item = (AgendaItem) knowledgeHelper.getMatch();
                final Cheese cheese = (Cheese) item.getTuple().getHandle().getObject();
                final int oldPrice = cheese.getPrice();
                cheese.setPrice(100);

                item.setActivationUnMatchListener(new ActivationUnMatchListener() {

                    public void unMatch(org.kie.api.runtime.rule.RuleRuntime wm,
                                        Match activation) {
                        cheese.setPrice(oldPrice);
                    }
                });
            }

            public void readExternal(ObjectInput in) throws IOException,
                    ClassNotFoundException {

            }

            public void writeExternal(ObjectOutput out) throws IOException {

            }

            public String getName() {
                return "default";
            }
        });

        assertEquals(50, cheese.getPrice());

        node1.assertLeftTuple(tuple,
                              context1,
                              workingMemory);


        agenda.unstageActivations();
        agenda.fireNextItem(null, 0, -1);
        assertEquals(100, cheese.getPrice());

        final PropagationContext context0 = pctxFactory.createPropagationContext(0,
                                                                                 PropagationContext.DELETION,
                                                                                 rule1,
                                                                                 null,
                                                                                 new DefaultFactHandle());

        node1.retractLeftTuple(tuple, context0, workingMemory);

        assertEquals(50, cheese.getPrice());
    }

    @Test
    public void testFilters() throws Exception {
        final AbstractWorkingMemory workingMemory = (AbstractWorkingMemory) ruleBase.newStatefulSession();

        final InternalAgenda agenda = (InternalAgenda) workingMemory.getAgenda();

        final Boolean[] filtered = new Boolean[]{false};

        workingMemory.addEventListener(new DefaultAgendaEventListener() {

            public void activationCancelled(ActivationCancelledEvent event,
                                            WorkingMemory workingMemory) {
                if (event.getCause() == MatchCancelledCause.FILTER) {
                    filtered[0] = true;
                }
            }
        });

        final Rule rule = new Rule("test-rule");
        final RuleTerminalNode node = new RuleTerminalNode(3,
                                                           new MockTupleSource(2),
                                                           rule,
                                                           rule.getLhs(),
                                                           0,
                                                           buildContext);

        final Map results = new HashMap();
        // add consequence
        rule.setConsequence(new org.drools.core.spi.Consequence() {
            private static final long serialVersionUID = 510l;

            public void evaluate(final KnowledgeHelper knowledgeHelper,
                                 final WorkingMemory workingMemory) {
                results.put("fired",
                            new Boolean(true));
            }

            public void readExternal(ObjectInput in) throws IOException,
                    ClassNotFoundException {

            }

            public void writeExternal(ObjectOutput out) throws IOException {

            }

            public String getName() {
                return "default";
            }
        });

        final RuleTerminalNodeLeftTuple tuple = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(1,
                                                                                                    "cheese"),
                                                                              node,
                                                                              true);
        final PropagationContext context = pctxFactory.createPropagationContext(0,
                                                                                PropagationContext.INSERTION,
                                                                                rule,
                                                                                null,
                                                                                new DefaultFactHandle());

        // test agenda is empty
        assertEquals(0,
                     agenda.getFocus().size());

        // True filter, activations should always add
        final AgendaFilter filterTrue = new

                AgendaFilter() {
                    public boolean accept(Activation item) {
                        return true;
                    }
                };

        rule.setNoLoop(false);
        node.assertLeftTuple(tuple,
                             context,
                             workingMemory);

        agenda.unstageActivations();

        // check there is an item to fire
        assertEquals(1,
                     agenda.getFocus().size());
        agenda.fireNextItem(filterTrue, 0, -1);

        // check focus is empty
        assertEquals(0,
                     agenda.getFocus().size());

        // make sure it also fired
        assertEquals(new Boolean(true),
                     results.get("fired"));

        assertEquals(false,
                     filtered[0].booleanValue());

        // clear the agenda and the result map
        agenda.clearAndCancel();
        results.clear();

        // False filter, activations should always be denied
        final AgendaFilter filterFalse = new

                AgendaFilter() {
                    public boolean accept(Activation item) {
                        return false;
                    }
                };

        rule.setNoLoop(false);
        node.assertLeftTuple(tuple,
                             context,
                             workingMemory);

        agenda.unstageActivations();

        // check we have an item to fire
        assertEquals(1,
                     agenda.getFocus().size());
        agenda.fireNextItem(filterFalse, 0, -1);

        // make sure the focus is empty
        assertEquals(0,
                     agenda.getFocus().size());

        // check the consequence never fired
        assertNull(results.get("fired"));

        assertEquals(true,
                     filtered[0].booleanValue());
    }

    @Test
    public void testFocusStack() throws ConsequenceException {
        final AbstractWorkingMemory workingMemory = (AbstractWorkingMemory) ruleBase.newStatefulSession();

        // create the consequence
        final Consequence consequence = new Consequence() {
            private static final long serialVersionUID = 510l;

            public void evaluate(KnowledgeHelper knowledgeHelper,
                                 WorkingMemory workingMemory) {
                // do nothing
            }

            public void readExternal(ObjectInput in) throws IOException,
                    ClassNotFoundException {

            }

            public void writeExternal(ObjectOutput out) throws IOException {

            }

            public String getName() {
                return "default";
            }
        };

        // create a rule for each agendaGroup
        final Rule rule0 = new Rule("test-rule0");
        final RuleTerminalNode node0 = new RuleTerminalNode(3,
                                                            new MockTupleSource(2),
                                                            rule0,
                                                            rule0.getLhs(),
                                                            0,
                                                            buildContext);
        rule0.setConsequence(consequence);
        final PropagationContext context0 = pctxFactory.createPropagationContext(0,
                                                                                 PropagationContext.INSERTION,
                                                                                 rule0,
                                                                                 null,
                                                                                 new DefaultFactHandle());

        final Rule rule1 = new Rule("test-rule1",
                                    "agendaGroup1");
        final RuleTerminalNode node1 = new RuleTerminalNode(5,
                                                            new MockTupleSource(4),
                                                            rule1,
                                                            rule1.getLhs(),
                                                            0,
                                                            buildContext);
        rule1.setConsequence(consequence);
        final PropagationContext context1 = pctxFactory.createPropagationContext(0,
                                                                                 PropagationContext.INSERTION,
                                                                                 rule1,
                                                                                 null,
                                                                                 new DefaultFactHandle());

        final Rule rule2 = new Rule("test-rule2",
                                    "agendaGroup2");
        final RuleTerminalNode node2 = new RuleTerminalNode(7,
                                                            new MockTupleSource(6),
                                                            rule2,
                                                            rule2.getLhs(),
                                                            0,
                                                            buildContext);
        rule2.setConsequence(consequence);
        final PropagationContext context2 = pctxFactory.createPropagationContext(0,
                                                                                 PropagationContext.INSERTION,
                                                                                 rule2,
                                                                                 null,
                                                                                 new DefaultFactHandle());

        final Rule rule3 = new Rule("test-rule3",
                                    "agendaGroup3");
        final RuleTerminalNode node3 = new RuleTerminalNode(9,
                                                            new MockTupleSource(8),
                                                            rule3,
                                                            rule3.getLhs(),
                                                            0,
                                                            buildContext);
        rule3.setConsequence(consequence);
        final PropagationContext context3 = pctxFactory.createPropagationContext(0,
                                                                                 PropagationContext.INSERTION,
                                                                                 rule3,
                                                                                 null,
                                                                                 new DefaultFactHandle());

        final RuleTerminalNodeLeftTuple tuple1 = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(1,
                                                                                                     "cheese"),
                                                                               node0,
                                                                               true);

        final RuleTerminalNodeLeftTuple tuple2 = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(2,
                                                                                                     "cheese"),
                                                                               node2,
                                                                               true);

        final RuleTerminalNodeLeftTuple tuple3 = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(3,
                                                                                                     "cheese"),
                                                                               node2,
                                                                               true);

        final RuleTerminalNodeLeftTuple tuple4 = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(4,
                                                                                                     "cheese"),
                                                                               node3,
                                                                               true);

        final RuleTerminalNodeLeftTuple tuple5 = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(5,
                                                                                                     "cheese"),
                                                                               node3,
                                                                               true);

        final InternalAgenda agenda = (InternalAgenda) workingMemory.getAgenda();

        // create the AgendaGroups
        final AgendaGroup agendaGroup1 = new AgendaGroupQueueImpl("agendaGroup1",
                                                                  ruleBase);
        agenda.addAgendaGroup(agendaGroup1);

        final AgendaGroup agendaGroup2 = new AgendaGroupQueueImpl("agendaGroup2",
                                                                  ruleBase);
        agenda.addAgendaGroup(agendaGroup2);

        final AgendaGroup agendaGroup3 = new AgendaGroupQueueImpl("agendaGroup3",
                                                                  ruleBase);
        agenda.addAgendaGroup(agendaGroup3);

        // focus at this point is MAIN
        assertEquals(0,
                     agenda.focusStackSize());

        node0.assertLeftTuple(tuple1,
                              context0,
                              workingMemory);

        agenda.unstageActivations();

        // check focus is main
        final AgendaGroup main = agenda.getAgendaGroup(AgendaGroup.MAIN);
        assertEquals(agenda.getFocus(),
                     main);
        // check main got the tuple
        assertEquals(1,
                     agenda.getFocus().size());
        node2.assertLeftTuple(tuple2,
                              context2,
                              workingMemory);

        agenda.unstageActivations();

        // main is still focus and this tuple went to agendaGroup 2
        assertEquals(1,
                     agenda.getFocus().size());

        // check agendaGroup2 still got the tuple
        assertEquals(1,
                     agendaGroup2.size());

        // make sure total agenda size reflects this
        assertEquals(2,
                     agenda.agendaSize());

        // put another one on agendaGroup 2
        node2.assertLeftTuple(tuple3,
                              context2,
                              workingMemory);

        agenda.unstageActivations();

        // main is still focus so shouldn't have increased
        assertEquals(1,
                     agenda.getFocus().size());

        // check agendaGroup2 still got the tuple
        assertEquals(2,
                     agendaGroup2.size());

        // make sure total agenda size reflects this
        assertEquals(3,
                     agenda.agendaSize());

        // set the focus to agendaGroup1, note agendaGroup1 has no activations
        agenda.setFocus("agendaGroup1");
        // add agendaGroup2 onto the focus stack
        agenda.setFocus("agendaGroup2");
        // finally add agendaGroup3 to the top of the focus stack
        agenda.setFocus("agendaGroup3");

        // agendaGroup3, the current focus, has no activations
        assertEquals(0,
                     agenda.getFocus().size());

        // add to agendaGroup 3
        node3.assertLeftTuple(tuple4,
                              context3,
                              workingMemory);

        agenda.unstageActivations();

        assertEquals(1,
                     agenda.getFocus().size());

        node3.assertLeftTuple(tuple5,
                              context3,
                              workingMemory);

        agenda.unstageActivations();

        // agendaGroup3 now has 2 activations
        assertEquals(2,
                     agenda.getFocus().size());
        // check totalAgendaSize still works
        assertEquals(5,
                     agenda.agendaSize());

        // ok now lets check that stacks work with fireNextItem
        agenda.fireNextItem(null, 0, -1);

        // agendaGroup3 should still be the current agendaGroup
        assertEquals(agenda.getFocus(),
                     agendaGroup3);
        // agendaGroup3 has gone from 2 to one activations
        assertEquals(1,
                     agenda.getFocus().size());
        // check totalAgendaSize has reduced too
        assertEquals(4,
                     agenda.agendaSize());

        // now repeat the process
        agenda.fireNextItem(null, 0, -1);

        // focus is still agendaGroup3, but now its empty
        assertEquals(agenda.getFocus(),
                     agendaGroup3);
        assertEquals(0,
                     agenda.getFocus().size());
        assertEquals(3,
                     agenda.agendaSize());

        // repeat fire again
        agenda.fireNextItem(null, 0, -1);

        // agendaGroup3 is empty so it should be popped from the stack making````````````````````
        // agendaGroup2
        // the current agendaGroup
        assertEquals(agendaGroup2,
                     agenda.getFocus());
        // agendaGroup2 had 2 activations, now it only has 1
        assertEquals(1,
                     agenda.getFocus().size());
        assertEquals(2,
                     agenda.agendaSize());

        // repeat fire again
        agenda.fireNextItem(null, 0, -1);

        assertEquals(agenda.getFocus(),
                     agendaGroup2);
        assertEquals(0,
                     agenda.getFocus().size());
        assertEquals(1,
                     agenda.agendaSize());

        // this last fire is more interesting as it demonstrates that
        // agendaGroup1 on
        // the stack before agendaGroup2 gets skipped as it has no activations
        agenda.fireNextItem(null, 0, -1);

        assertEquals(agenda.getFocus(),
                     main);
        assertEquals(0,
                     agenda.getFocus().size());
        assertEquals(0,
                     agenda.agendaSize());

    }

    //
    @Test
    public void testAutoFocus() throws ConsequenceException {
        final AbstractWorkingMemory workingMemory = (AbstractWorkingMemory) ruleBase.newStatefulSession();
        final InternalAgenda agenda = (InternalAgenda) workingMemory.getAgenda();

        // create the agendaGroup
        final AgendaGroup agendaGroup = new AgendaGroupQueueImpl("agendaGroup",
                                                                 ruleBase);
        agenda.addAgendaGroup(agendaGroup);

        // create the consequence
        final Consequence consequence = new Consequence() {
            private static final long serialVersionUID = 510l;

            public void evaluate(KnowledgeHelper knowledgeHelper,
                                 WorkingMemory workingMemory) {
                // do nothing
            }

            public void readExternal(ObjectInput in) throws IOException,
                    ClassNotFoundException {

            }

            public void writeExternal(ObjectOutput out) throws IOException {

            }

            public String getName() {
                return "default";
            }
        };


        // create a rule for the agendaGroup
        final Rule rule = new Rule("test-rule",
                                   "agendaGroup");
        final RuleTerminalNode node = new RuleTerminalNode(2,
                                                           new MockTupleSource(2),
                                                           rule,
                                                           rule.getLhs(),
                                                           0,
                                                           buildContext);

        final RuleTerminalNodeLeftTuple tuple = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(1,
                                                                                                    "cheese"),
                                                                              node,
                                                                              true);
        rule.setConsequence(consequence);
        final PropagationContext context = pctxFactory.createPropagationContext(0,
                                                                                PropagationContext.INSERTION,
                                                                                rule,
                                                                                null,
                                                                                new DefaultFactHandle());

        // first test that autoFocus=false works. Here the rule should not fire
        // as its agendaGroup does not have focus.
        rule.setAutoFocus(false);

        node.assertLeftTuple(tuple,
                             context,
                             workingMemory);

        agenda.unstageActivations();

        // check activation as added to the agendaGroup
        assertEquals(1,
                     agendaGroup.size());

        // fire next item, agendaGroup should not fire as its not on the focus stack
        // and thus should retain its sinle activation
        agenda.fireNextItem(null, 0, -1);
        assertEquals(1,
                     agendaGroup.size());

        // Clear the agenda we we can test again
        agenda.clearAndCancel();
        assertEquals(0,
                     agendaGroup.size());

        // Now test that autoFocus=true works. Here the rule should fire as its
        // agendaGroup gets the focus when the activation is created.
        rule.setAutoFocus(true);

        node.assertLeftTuple(tuple,
                             context,
                             workingMemory);

        agenda.unstageActivations();

        assertEquals(1,
                     agendaGroup.size());
        agenda.fireNextItem(null, 0, -1);
        assertEquals(0,
                     agendaGroup.size());
    }

    @Test
    public void testAgendaGroupLockOnActive() {
        final AbstractWorkingMemory workingMemory = (AbstractWorkingMemory) ruleBase.newStatefulSession();
        final InternalAgenda agenda = (InternalAgenda) workingMemory.getAgenda();

        // create the agendaGroup
        final InternalAgendaGroup agendaGroup = new AgendaGroupQueueImpl("agendaGroup",
                                                                         ruleBase);
        agenda.addAgendaGroup(agendaGroup);

        // create a rule for the agendaGroup
        final Rule rule = new Rule("test-rule",
                                   "agendaGroup");
        final RuleTerminalNode node = new RuleTerminalNode(2,
                                                           new MockTupleSource(2),
                                                           rule,
                                                           rule.getLhs(),
                                                           0,
                                                           buildContext);

        final RuleTerminalNodeLeftTuple tuple = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(1,
                                                                                                    "cheese"),
                                                                              node,
                                                                              true);

        final PropagationContext context = pctxFactory.createPropagationContext(0,
                                                                                PropagationContext.INSERTION,
                                                                                rule,
                                                                                null,
                                                                                new DefaultFactHandle());

        // When both the rule is lock-on-active and the agenda group is active, activations should be ignored
        rule.setLockOnActive(true);
        ((InternalRuleFlowGroup) agendaGroup).setAutoDeactivate(false);
        agendaGroup.setActive(true);
        node.assertLeftTuple(tuple,
                             context,
                             workingMemory);
        // activation should be ignored
        assertEquals(0,
                     agendaGroup.size());

        // lock-on-active is now false so activation should propagate
        rule.setLockOnActive(false);
        node.assertLeftTuple(tuple,
                             context,
                             workingMemory);

        agenda.unstageActivations();

        assertEquals(1,
                     agendaGroup.size());

        // even if lock-on-active is true, unless the agenda group is active the activation will still propagate
        rule.setLockOnActive(true);
        agendaGroup.setActive(false);
        node.assertLeftTuple(tuple,
                             context,
                             workingMemory);
        agenda.unstageActivations();
        assertEquals(2,
                     agendaGroup.size());
    }

    @Test
    public void testActivationGroup() {
        final AbstractWorkingMemory workingMemory = (AbstractWorkingMemory) ruleBase.newStatefulSession();

        final InternalAgenda agenda = (InternalAgenda) workingMemory.getAgenda();

        final List list = new ArrayList();

        // create the consequence
        final Consequence consequence = new Consequence() {
            private static final long serialVersionUID = 510l;

            public void evaluate(KnowledgeHelper knowledgeHelper,
                                 WorkingMemory workingMemory) {
                list.add(knowledgeHelper.getRule());
            }

            public void readExternal(ObjectInput in) throws IOException,
                    ClassNotFoundException {

            }

            public void writeExternal(ObjectOutput out) throws IOException {

            }

            public String getName() {
                return "default";
            }
        };

        // create a rule for each agendaGroup
        final Rule rule0 = new Rule("test-rule0");
        rule0.setActivationGroup("activation-group-0");
        final RuleTerminalNode node0 = new RuleTerminalNode(3,
                                                            new MockTupleSource(2),
                                                            rule0,
                                                            rule0.getLhs(),
                                                            0,
                                                            buildContext);
        rule0.setConsequence(consequence);
        final PropagationContext context0 = pctxFactory.createPropagationContext(0,
                                                                                 PropagationContext.INSERTION,
                                                                                 rule0,
                                                                                 null,
                                                                                 new DefaultFactHandle());

        final Rule rule1 = new Rule("test-rule1");
        rule1.setActivationGroup("activation-group-0");
        rule1.setSalience(new SalienceInteger(10));
        final RuleTerminalNode node1 = new RuleTerminalNode(5,
                                                            new MockTupleSource(4),
                                                            rule1,
                                                            rule1.getLhs(),
                                                            0,
                                                            buildContext);
        rule1.setConsequence(consequence);
        final PropagationContext context1 = pctxFactory.createPropagationContext(0,
                                                                                 PropagationContext.INSERTION,
                                                                                 rule1,
                                                                                 null,
                                                                                 new DefaultFactHandle());

        final Rule rule2 = new Rule("test-rule2");
        rule2.setSalience(new SalienceInteger(-5));
        final RuleTerminalNode node2 = new RuleTerminalNode(7,
                                                            new MockTupleSource(6),
                                                            rule2,
                                                            rule2.getLhs(),
                                                            0,
                                                            buildContext);
        rule2.setConsequence(consequence);
        final PropagationContext context2 = pctxFactory.createPropagationContext(0,
                                                                                 PropagationContext.INSERTION,
                                                                                 rule2,
                                                                                 null,
                                                                                 new DefaultFactHandle());

        final Rule rule3 = new Rule("test-rule3",
                                    "agendaGroup3");
        rule3.setSalience(new SalienceInteger(-10));
        rule3.setActivationGroup("activation-group-3");
        final RuleTerminalNode node3 = new RuleTerminalNode(9,
                                                            new MockTupleSource(8),
                                                            rule3,
                                                            rule3.getLhs(),
                                                            0,
                                                            buildContext);
        rule3.setConsequence(consequence);
        final PropagationContext context3 = pctxFactory.createPropagationContext(0,
                                                                                 PropagationContext.INSERTION,
                                                                                 rule3,
                                                                                 null,
                                                                                 new DefaultFactHandle());

        final RuleTerminalNodeLeftTuple tuple1 = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(1, "cheese"), node1, true);
        final RuleTerminalNodeLeftTuple tuple3 = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(1, "cheese"), node1, true);
        final RuleTerminalNodeLeftTuple tuple4 = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(1, "cheese"), node1, true);
        final RuleTerminalNodeLeftTuple tuple5 = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(1, "cheese"), node1, true);
        final RuleTerminalNodeLeftTuple tuple6 = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(1, "cheese"), node1, true);
        final RuleTerminalNodeLeftTuple tuple7 = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(1, "cheese"), node2, true);
        final RuleTerminalNodeLeftTuple tuple8 = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(1, "cheese"), node3, true);

        // Assert the tuple and check it was added to activation-group-0
        node0.assertLeftTuple(tuple1,
                              context0,
                              workingMemory);
        agenda.unstageActivations();
        final ActivationGroup activationGroup0 = agenda.getActivationGroup("activation-group-0");
        assertEquals(1,
                     activationGroup0.size());

        // Removing a tuple should remove the activation from the activation-group-0 again
        node0.retractLeftTuple(tuple1,
                               context0,
                               workingMemory);
        assertEquals(0,
                     activationGroup0.size());

        // Assert the tuple again and check it was added to activation-group-0
        node0.assertLeftTuple(tuple3,
                              context0,
                              workingMemory);
        agenda.unstageActivations();
        assertEquals(1,
                     activationGroup0.size());

        // Assert another tuple and check it was added to activation-group-0
        node1.assertLeftTuple(tuple4,
                              context1,
                              workingMemory);
        agenda.unstageActivations();
        assertEquals(2,
                     activationGroup0.size());

        // There should now be two potential activations to fire
        assertEquals(2,
                     agenda.focusStackSize());

        // The first tuple should fire, adding itself to the List and clearing and cancelling the other Activations in the activation-group-0
        agenda.fireNextItem(null, 0, -1);

        // Make sure the activation-group-0 is clear
        assertEquals(0,
                     activationGroup0.size());

        // Make sure the Agenda  is  empty
        assertEquals(0,
                     agenda.focusStackSize());

        // List should only have a single item, "rule0"
        assertEquals(1,
                     list.size());
        assertSame(rule1,
                   list.get(0));

        list.clear();

        //-------------------
        // Now try a more complex scenario involving  two Xor Groups and one  rule not in a Group
        node0.assertLeftTuple(tuple5,
                              context0,
                              workingMemory);
        node1.assertLeftTuple(tuple6,
                              context1,
                              workingMemory);
        node2.assertLeftTuple(tuple7,
                              context2,
                              workingMemory);
        node3.assertLeftTuple(tuple8,
                              context3,
                              workingMemory);
        agenda.unstageActivations();

        // activation-group-0 should be populated again
        assertEquals(2,
                     activationGroup0.size());

        // make sure the activation-group-3 is cleared when we can clear the Agenda Group for the activation that is in both
        final ActivationGroup activationGroup3 = agenda.getActivationGroup("activation-group-3");

        assertEquals(4,
                     agenda.agendaSize());
        assertEquals(1,
                     activationGroup3.size());

        agenda.clearAndCancelAgendaGroup("agendaGroup3");
        assertEquals(3,
                     agenda.agendaSize());
        assertEquals(0,
                     activationGroup3.size());

        // Activation for activation-group-0 should be next - the activation in no activation/agenda group should remain on the agenda
        agenda.fireNextItem(null, 0, -1);
        assertEquals(1,
                     agenda.agendaSize());
        assertEquals(0,
                     activationGroup0.size());

        // Fire  the  last activation and  make sure the Agenda Empties
        agenda.fireNextItem(null, 0, -1);
        assertEquals(0,
                     agenda.agendaSize());

        assertEquals(2,
                     list.size());
        assertEquals(rule1,
                     list.get(0));
        assertEquals(rule2,
                     list.get(1));

    }

    /**
     * Basic RuleFlowGroup test where there are three rules, each in their own
     * RuleFlowGroup.  First only rule-flow-group-0 is activated and rule0 is
     * executed.  When the two remaining groups are activated, the rule with the
     * highest priority is executed first.
     */
    @Test
    public void testRuleFlowGroup() {
        final AbstractWorkingMemory workingMemory = (AbstractWorkingMemory) ruleBase.newStatefulSession();

        final InternalAgenda agenda = (InternalAgenda) workingMemory.getAgenda();

        final List list = new ArrayList();

        // create the consequence
        final Consequence consequence = new Consequence() {
            private static final long serialVersionUID = 510l;

            public void evaluate(KnowledgeHelper knowledgeHelper,
                                 WorkingMemory workingMemory) {
                list.add(knowledgeHelper.getRule());
            }

            public void readExternal(ObjectInput in) throws IOException,
                    ClassNotFoundException {

            }

            public void writeExternal(ObjectOutput out) throws IOException {

            }

            public String getName() {
                return "default";
            }
        };

        // create a rule for each rule flow groups
        final Rule rule0 = new Rule("test-rule0");
        rule0.setAgendaGroup("rule-flow-group-0");
        rule0.setConsequence(consequence);

        final RuleTerminalNode node0 = new RuleTerminalNode(3,
                                                            new MockTupleSource(2),
                                                            rule0,
                                                            rule0.getLhs(),
                                                            0,
                                                            buildContext);

        final Rule rule1 = new Rule("test-rule1");
        rule1.setAgendaGroup("rule-flow-group-1");
        rule1.setConsequence(consequence);

        final RuleTerminalNode node1 = new RuleTerminalNode(4,
                                                            new MockTupleSource(2),
                                                            rule1,
                                                            rule1.getLhs(),
                                                            0,
                                                            buildContext);

        final Rule rule2 = new Rule("test-rule2");
        rule2.setAgendaGroup("rule-flow-group-2");
        rule2.setConsequence(consequence);
        rule2.setSalience(new SalienceInteger(10));

        final RuleTerminalNode node2 = new RuleTerminalNode(5,
                                                            new MockTupleSource(2),
                                                            rule2,
                                                            rule2.getLhs(),
                                                            0,
                                                            buildContext);

        final PropagationContext context0 = pctxFactory.createPropagationContext(0,
                                                                                 PropagationContext.INSERTION,
                                                                                 rule0,
                                                                                 null,
                                                                                 new DefaultFactHandle());

        final RuleFlowGroup ruleFlowGroup0 = agenda.getRuleFlowGroup("rule-flow-group-0");
        final RuleFlowGroup ruleFlowGroup1 = agenda.getRuleFlowGroup("rule-flow-group-1");
        final RuleFlowGroup ruleFlowGroup2 = agenda.getRuleFlowGroup("rule-flow-group-2");

        final RuleTerminalNodeLeftTuple tuple0 = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(1,
                                                                                                     "cheese"),
                                                                               node0,
                                                                               true);
        node0.assertLeftTuple(tuple0,
                              context0,
                              workingMemory);

        final RuleTerminalNodeLeftTuple tuple1 = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(1,
                                                                                                     "cheese"),
                                                                               node1,
                                                                               true);
        node0.assertLeftTuple(tuple1,
                              context0,
                              workingMemory);

        final RuleTerminalNodeLeftTuple tuple2 = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(1,
                                                                                                     "cheese"),
                                                                               node2,
                                                                               true);
        node1.assertLeftTuple(tuple2,
                              context0,
                              workingMemory);

        final RuleTerminalNodeLeftTuple tuple3 = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(1,
                                                                                                     "cheese"),
                                                                               node0,
                                                                               true);
        node2.assertLeftTuple(tuple3,
                              context0,
                              workingMemory);
        agenda.unstageActivations();

        assertEquals(2,
                     ruleFlowGroup0.size());
        assertEquals(1,
                     ruleFlowGroup1.size());
        assertEquals(1,
                     ruleFlowGroup2.size());
        assertEquals(4,
                     agenda.agendaSize());

        // Activate the RuleFlowGroup, the nodes stay in the group, but should now also be in the Agenda
        agenda.activateRuleFlowGroup("rule-flow-group-0");
        assertEquals(2,
                     ruleFlowGroup0.size());
        assertEquals(4,
                     agenda.agendaSize());

        // As we fire each rule they are removed from both the Agenda and the RuleFlowGroup
        agenda.fireNextItem(null, 0, -1);
        assertEquals(1,
                     ruleFlowGroup0.size());
        assertEquals(3,
                     agenda.agendaSize());

        // After firing all activations of RuleFlowGroup 0, the agenda is empty
        agenda.fireNextItem(null, 0, -1);
        assertEquals(0,
                     ruleFlowGroup0.size());
        assertEquals(2,
                     agenda.agendaSize());

        // Now we activate two RuleFlowGroups together
        // All their activations should be added to the agenda.
        agenda.activateRuleFlowGroup("rule-flow-group-1");
        agenda.activateRuleFlowGroup("rule-flow-group-2");
        assertEquals(1,
                     ruleFlowGroup1.size());
        assertEquals(1,
                     ruleFlowGroup2.size());
        assertEquals(2,
                     agenda.agendaSize());

        // we set the salience higher on rule2, so it sould fire first and empty ruleFlowGroup2
        agenda.fireNextItem(null, 0, -1);
        assertEquals(1,
                     ruleFlowGroup1.size());
        assertEquals(0,
                     ruleFlowGroup2.size());
        assertEquals(1,
                     agenda.agendaSize());

        // this is the last activation, so everything should be empty after this
        agenda.fireNextItem(null, 0, -1);
        assertEquals(0,
                     ruleFlowGroup0.size());
        assertEquals(0,
                     ruleFlowGroup1.size());
        assertEquals(0,
                     ruleFlowGroup2.size());
        assertEquals(0,
                     agenda.agendaSize());
    }

    /**
     * RuleFlowGroup test that makes sure that, if new activations are created
     * for an active RuleFlowGroup, those activations get added to the agenda
     * directly as well.
     */
    @Test
    public void testRuleFlowGroup1() {
        final AbstractWorkingMemory workingMemory = (AbstractWorkingMemory) ruleBase.newStatefulSession();

        final InternalAgenda agenda = (InternalAgenda) workingMemory.getAgenda();

        // create rule1
        final Consequence consequence1 = new Consequence() {
            private static final long serialVersionUID = 510l;

            public void evaluate(KnowledgeHelper knowledgeHelper,
                                 WorkingMemory workingMemory) {
                // do nothing
            }

            public void readExternal(ObjectInput in) throws IOException,
                    ClassNotFoundException {

            }

            public void writeExternal(ObjectOutput out) throws IOException {

            }

            public String getName() {
                return "default";
            }
        };

        final Rule rule1 = new Rule("test-rule1");
        rule1.setAgendaGroup("rule-flow-group-0");
        rule1.setConsequence(consequence1);

        final RuleTerminalNode node1 = new RuleTerminalNode(4,
                                                            new MockTupleSource(2),
                                                            rule1,
                                                            rule1.getLhs(),
                                                            0,
                                                            buildContext);

        // create context
        final PropagationContext context0 = pctxFactory.createPropagationContext(0,
                                                                                 PropagationContext.INSERTION,
                                                                                 rule1,
                                                                                 null,
                                                                                 new DefaultFactHandle());

        // create rule0
        final Consequence consequence0 = new

                Consequence() {
                    private static final long serialVersionUID = 510l;

                    public void evaluate(KnowledgeHelper knowledgeHelper,
                                         WorkingMemory w) {
                        // activate rule1
                        final RuleTerminalNodeLeftTuple tuple1 = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(1,
                                                                                                                     "cheese"),
                                                                                               node1,
                                                                                               true);
                        node1.assertLeftTuple(tuple1,
                                              context0,
                                              workingMemory);
                    }

                    public void readExternal(ObjectInput in) throws IOException,
                            ClassNotFoundException {

                    }

                    public void writeExternal(ObjectOutput out) throws IOException {

                    }

                    public String getName() {
                        return "default";
                    }
                };

        final Rule rule0 = new Rule("test-rule0");
        rule0.setAgendaGroup("rule-flow-group-0");
        rule0.setConsequence(consequence0);

        final RuleTerminalNode node0 = new RuleTerminalNode(3,
                                                            new MockTupleSource(2),
                                                            rule0,
                                                            rule0.getLhs(),
                                                            0,
                                                            buildContext);

        final RuleFlowGroup ruleFlowGroup0 = agenda.getRuleFlowGroup("rule-flow-group-0");

        // Create one activation for rule0 only
        final RuleTerminalNodeLeftTuple tuple0 = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(1,
                                                                                                     "cheese"),
                                                                               node0,
                                                                               true);
        node0.assertLeftTuple(tuple0,
                              context0,
                              workingMemory);
        agenda.unstageActivations();

        // RuleFlowGroup should be populated, but the agenda shouldn't be
        assertEquals(1,
                     ruleFlowGroup0.size());

        // Activate the RuleFlowGroup, the activation stays in the group, but should now also be in the Agenda
        agenda.activateRuleFlowGroup("rule-flow-group-0");
        assertEquals(1,
                     ruleFlowGroup0.size());

        // As we fire the rule, an new activation is created for rule1, and it should be added to group AND the agenda.
        agenda.fireNextItem(null, 0, -1);
        assertEquals(1,
                     ruleFlowGroup0.size());

        // After firing all activations of RuleFlowGroup 0, the agenda is empty
        agenda.fireNextItem(null, 0, -1);
        assertEquals(0,
                     ruleFlowGroup0.size());
        assertEquals(0,
                     agenda.agendaSize());
    }

    /**
     * RuleFlowGroup test that makes sure that, if an activation in an active
     * RuleFlowGroup gets deactivated, the activation is no longer executed.
     */
    @Test
    public void testRuleFlowGroup2() {
        final AbstractWorkingMemory workingMemory = (AbstractWorkingMemory) ruleBase.newStatefulSession();

        final InternalAgenda agenda = (InternalAgenda) workingMemory.getAgenda();

        // create rule1
        final Consequence consequence1 = new Consequence() {
            private static final long serialVersionUID = 510l;

            public void evaluate(KnowledgeHelper knowledgeHelper,
                                 WorkingMemory workingMemory) {
                // do nothing
            }

            public void readExternal(ObjectInput in) throws IOException,
                    ClassNotFoundException {

            }

            public void writeExternal(ObjectOutput out) throws IOException {

            }

            public String getName() {
                return "default";
            }
        };

        final Rule rule1 = new Rule("test-rule1");
        rule1.setAgendaGroup("rule-flow-group-0");
        rule1.setConsequence(consequence1);

        final RuleTerminalNode node1 = new RuleTerminalNode(4,
                                                            new MockTupleSource(2),
                                                            rule1,
                                                            rule1.getLhs(),
                                                            0,
                                                            buildContext);

        // create context
        final PropagationContext context0 = pctxFactory.createPropagationContext(0,
                                                                                 PropagationContext.INSERTION,
                                                                                 rule1,
                                                                                 null,
                                                                                 new DefaultFactHandle());

        final RuleTerminalNodeLeftTuple tuple1 = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(1,
                                                                                                     "cheese"),
                                                                               node1,
                                                                               true);

        // create rule0
        final Consequence consequence0 = new

                Consequence() {
                    private static final long serialVersionUID = 510l;

                    public void evaluate(KnowledgeHelper knowledgeHelper,
                                         WorkingMemory w) {
                        // deactivate rule1
                        node1.retractLeftTuple(tuple1,
                                               context0,
                                               workingMemory);
                    }

                    public void readExternal(ObjectInput in) throws IOException,
                            ClassNotFoundException {

                    }

                    public void writeExternal(ObjectOutput out) throws IOException {

                    }

                    public String getName() {
                        return "default";
                    }
                };

        final Rule rule0 = new Rule("test-rule0");
        rule0.setAgendaGroup("rule-flow-group-0");
        rule0.setConsequence(consequence0);
        rule0.setSalience(new SalienceInteger(10));

        final RuleTerminalNode node0 = new RuleTerminalNode(3,
                                                            new MockTupleSource(2),
                                                            rule0,
                                                            rule0.getLhs(),
                                                            0,
                                                            buildContext);

        final RuleFlowGroup ruleFlowGroup0 = agenda.getRuleFlowGroup("rule-flow-group-0");

        // Create an activation for both rules
        final RuleTerminalNodeLeftTuple tuple0 = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(1,
                                                                                                     "cheese"),
                                                                               node0,
                                                                               true);
        node0.assertLeftTuple(tuple0,
                              context0,
                              workingMemory);

        node1.assertLeftTuple(tuple1,
                              context0,
                              workingMemory);
        agenda.unstageActivations();

        // RuleFlowGroup should be populated
        assertEquals(2,
                     ruleFlowGroup0.size());

        // Activate the RuleFlowGroup, the activations stay in the group, but should now also be in the Agenda
        agenda.activateRuleFlowGroup("rule-flow-group-0");
        assertEquals(2,
                     ruleFlowGroup0.size());

        // As we fire the rule, rule0 should execute first, as it has higher salience.
        // Rule0 should deactivate rule1 as well, so the everything should be empty
        agenda.fireNextItem(null, 0, -1);
        assertEquals(0,
                     ruleFlowGroup0.size());

        agenda.fireNextItem(null, 0, -1);
        assertEquals(0,
                     ruleFlowGroup0.size());

    }

    /**
     * RuleFlowGroup test that makes sure that, when deactivating a RuleFlowGroup,
     * all activations for that group are no longer on the agenda.  When
     * reactivating the RuleFlowGroup however, they get added to the agenda again.
     */
    @Test
    public void testRuleFlowGroup3() {
        final AbstractWorkingMemory workingMemory = (AbstractWorkingMemory) ruleBase.newStatefulSession();

        final InternalAgenda agenda = (InternalAgenda) workingMemory.getAgenda();

        // create rule0
        final Consequence consequence0 = new Consequence() {
            private static final long serialVersionUID = 510l;

            public void evaluate(KnowledgeHelper knowledgeHelper,
                                 WorkingMemory w) {
                // do nothing
            }

            public void readExternal(ObjectInput in) throws IOException,
                    ClassNotFoundException {

            }

            public void writeExternal(ObjectOutput out) throws IOException {

            }

            public String getName() {
                return "default";
            }
        };

        final Rule rule0 = new Rule("test-rule0");
        rule0.setAgendaGroup("rule-flow-group-0");
        rule0.setConsequence(consequence0);

        final RuleTerminalNode node0 = new RuleTerminalNode(1,
                                                            new MockTupleSource(2),
                                                            rule0,
                                                            rule0.getLhs(),
                                                            0,
                                                            buildContext);

        final RuleFlowGroup ruleFlowGroup0 = agenda.getRuleFlowGroup("rule-flow-group-0");

        // create context
        final PropagationContext context0 = pctxFactory.createPropagationContext(0,
                                                                                 PropagationContext.INSERTION,
                                                                                 rule0,
                                                                                 null,
                                                                                 new DefaultFactHandle());

        // Create two activation for this rule
        final RuleTerminalNodeLeftTuple tuple0 = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(1,
                                                                                                     "cheese"),
                                                                               node0,
                                                                               true);
        node0.assertLeftTuple(tuple0,
                              context0,
                              workingMemory);
        final RuleTerminalNodeLeftTuple tuple1 = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(1,
                                                                                                     "cheese"),
                                                                               node0,
                                                                               true);
        node0.assertLeftTuple(tuple1,
                              context0,
                              workingMemory);
        agenda.unstageActivations();

        // RuleFlowGroup should be populated, but the agenda shouldn't be
        assertEquals(2,
                     ruleFlowGroup0.size());

        // Activate the RuleFlowGroup
        agenda.activateRuleFlowGroup("rule-flow-group-0");
        assertEquals(2,
                     ruleFlowGroup0.size());

        // Reactivate an already active RuleFlowGroup should not have any effect
        agenda.activateRuleFlowGroup("rule-flow-group-0");
        assertEquals(2,
                     ruleFlowGroup0.size());

        // Deactivate the RuleFlowGroup, the activations should be removed from
        // the agenda but still in the RuleFlowGroup
        agenda.deactivateRuleFlowGroup("rule-flow-group-0");
        assertEquals(2,
                     ruleFlowGroup0.size());

        // Reactivate the RuleFlowGroup, the activations stay in the group, but
        // should now also be in the Agenda again
        agenda.activateRuleFlowGroup("rule-flow-group-0");
        assertEquals(2,
                     ruleFlowGroup0.size());

    }

    /**
     * Test auto-deactivation of RuleFlowGroup.
     */
    @Test
    public void testRuleFlowGroup4() {
        IdGenerator idGenerator = ruleBase.getReteooBuilder().getIdGenerator();
        final InternalWorkingMemory workingMemory = (InternalWorkingMemory) ruleBase.newStatefulSession();
        ;

        final InternalAgenda agenda = (InternalAgenda) workingMemory.getAgenda();

        // create rule0
        final Consequence consequence0 = new Consequence() {
            private static final long serialVersionUID = 510l;

            public void evaluate(KnowledgeHelper knowledgeHelper,
                                 WorkingMemory w) {
                // do nothing
            }

            public void readExternal(ObjectInput in) throws IOException,
                    ClassNotFoundException {

            }

            public void writeExternal(ObjectOutput out) throws IOException {

            }

            public String getName() {
                return "default";
            }
        };

        final Rule rule0 = new Rule("test-rule0");
        rule0.setAgendaGroup("rule-flow-group-0");
        rule0.setConsequence(consequence0);

        final RuleTerminalNode node0 = new RuleTerminalNode(idGenerator.getNextId(),
                                                            new MockTupleSource(idGenerator.getNextId()),
                                                            rule0,
                                                            rule0.getLhs(),
                                                            0,
                                                            buildContext);

        final RuleFlowGroup ruleFlowGroup0 = agenda.getRuleFlowGroup("rule-flow-group-0");
        assertTrue(ruleFlowGroup0.isAutoDeactivate());
        ruleFlowGroup0.setAutoDeactivate(false);
        assertFalse(ruleFlowGroup0.isAutoDeactivate());

        // create context
        final PropagationContext context0 = pctxFactory.createPropagationContext(0,
                                                                                 PropagationContext.INSERTION,
                                                                                 rule0,
                                                                                 null,
                                                                                 new DefaultFactHandle());

        // Create an activation for this rule
        final RuleTerminalNodeLeftTuple tuple0 = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(1,
                                                                                                     "cheese"),
                                                                               node0,
                                                                               true);
        node0.assertLeftTuple(tuple0,
                              context0,
                              workingMemory);

        workingMemory.fireAllRules();

        // RuleFlowGroup should be populated, but the agenda shouldn't be
        assertEquals(1,
                     ruleFlowGroup0.size());

        // Activate the RuleFlowGroup
        agenda.activateRuleFlowGroup("rule-flow-group-0");
        assertEquals(1,
                     ruleFlowGroup0.size());

        // Execute activation
        agenda.fireNextItem(null, 0, -1);
        assertEquals(0,
                     ruleFlowGroup0.size());
        assertTrue(ruleFlowGroup0.isActive());

        // Set auto-deactivation status to true
        ruleFlowGroup0.setAutoDeactivate(true);
        assertTrue(ruleFlowGroup0.isAutoDeactivate());
        agenda.fireNextItem(null, 0, -1);
        assertFalse(ruleFlowGroup0.isActive());

        // Add another activation and activate RuleFlowGroup again
        final RuleTerminalNodeLeftTuple tuple1 = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(1,
                                                                                                     "cheese"),
                                                                               node0,
                                                                               true);
        node0.assertLeftTuple(tuple1,
                              context0,
                              workingMemory);
        agenda.unstageActivations();
        agenda.activateRuleFlowGroup("rule-flow-group-0");
        assertEquals(1,
                     ruleFlowGroup0.size());
        assertTrue(ruleFlowGroup0.isActive());

        // Execute the activation, the RuleFlowGroup should automatically deactivate
        agenda.fireNextItem(null, 0, -1);
        assertEquals(0,
                     ruleFlowGroup0.size());
        workingMemory.executeQueuedActions();
        assertEquals(0, ruleFlowGroup0.size());
        agenda.fireNextItem(null, 0, -1);
        assertFalse(ruleFlowGroup0.isActive());

        // A new activation should now be added to the RuleFlowGroup but not to the agenda
        final RuleTerminalNodeLeftTuple tuple2 = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(1,
                                                                                                     "cheese"),
                                                                               node0,
                                                                               true);
        node0.assertLeftTuple(tuple2,
                              context0,
                              workingMemory);
        agenda.unstageActivations();
        assertEquals(1,
                     ruleFlowGroup0.size());
    }

    /**
     * Test auto-deactivation of empty ruleflow group.
     */
    @Test
    public void testRuleFlowGroup5() {
        final AbstractWorkingMemory workingMemory = (AbstractWorkingMemory) ruleBase.newStatefulSession();

        final InternalAgenda agenda = (InternalAgenda) workingMemory.getAgenda();

        // create rule0
        final Consequence consequence0 = new Consequence() {
            private static final long serialVersionUID = 510l;

            public void evaluate(KnowledgeHelper knowledgeHelper,
                                 WorkingMemory w) {
                // do nothing
            }

            public void readExternal(ObjectInput in) throws IOException,
                    ClassNotFoundException {

            }

            public void writeExternal(ObjectOutput out) throws IOException {

            }

            public String getName() {
                return "default";
            }
        };

        final Rule rule0 = new Rule("test-rule0");
        rule0.setRuleFlowGroup("rule-flow-group-0");
        rule0.setConsequence(consequence0);

        final RuleFlowGroup ruleFlowGroup0 = agenda.getRuleFlowGroup("rule-flow-group-0");
        assertTrue(ruleFlowGroup0.isAutoDeactivate());

        // RuleFlowGroup should be empty, as well as the agenda
        assertEquals(0,
                     ruleFlowGroup0.size());
        assertEquals(0,
                     agenda.agendaSize());

        // @TODO FIXME (mdp)
        //        // Activate the RuleFlowGroup, the activations stay in the group, but
        //        // should now also be in the Agenda
        //        agenda.activateRuleFlowGroup( "rule-flow-group-0" );
        //        assertEquals( 0,
        //                      ruleFlowGroup0.size() );
        //        assertEquals( 0,
        //                      agenda.agendaSize() );
        //        workingMemory.executeQueuedActions();
        //
        //        assertFalse( ruleFlowGroup0.isActive() );
    }

    @Test
    public void testRuleFlowGroupLockOnActive() {
        final AbstractWorkingMemory workingMemory = (AbstractWorkingMemory) ruleBase.newStatefulSession();
        final InternalAgenda agenda = (InternalAgenda) workingMemory.getAgenda();

        // create the agendaGroup
        //final AgendaGroupImpl agendaGroup = new AgendaGroupImpl( "agendaGroup" );
        //agenda.addAgendaGroup( agendaGroup );

        final RuleFlowGroup ruleFlowGroup = (RuleFlowGroup) agenda.getRuleFlowGroup("rule-flow-group-0");

        // create a rule for the agendaGroup
        final Rule rule = new Rule("test-rule");
        rule.setAgendaGroup("rule-flow-group-0");
        final RuleTerminalNode node = new RuleTerminalNode(2,
                                                           new MockTupleSource(2),
                                                           rule,
                                                           rule.getLhs(),
                                                           0,
                                                           buildContext);

        final RuleTerminalNodeLeftTuple tuple1 = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(1, "cheese"), node, true);
        final RuleTerminalNodeLeftTuple tuple2 = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(1, "cheese"), node, true);
        final RuleTerminalNodeLeftTuple tuple3 = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(1, "cheese"), node, true);

        final PropagationContext context = pctxFactory.createPropagationContext(0,
                                                                                PropagationContext.INSERTION,
                                                                                rule,
                                                                                null,
                                                                                new DefaultFactHandle());

        // When both the rule is lock-on-active and the agenda group is active, activations should be ignored
        rule.setLockOnActive(true);
        ruleFlowGroup.setAutoDeactivate(false);
        ((InternalRuleFlowGroup) ruleFlowGroup).setActive(true);
        node.assertLeftTuple(tuple1,
                             context,
                             workingMemory);
        // activation should be ignored
        assertEquals(0, ruleFlowGroup.size());

        // lock-on-active is now false so activation should propagate
        rule.setLockOnActive(false);
        node.assertLeftTuple(tuple2,
                             context,
                             workingMemory);
        agenda.unstageActivations();
        assertEquals(1,
                     ruleFlowGroup.size());

        // even if lock-on-active is true, unless the agenda group is active the activation will still propagate
        rule.setLockOnActive(true);
        ((InternalAgendaGroup) ruleFlowGroup).setActive(false);
        node.assertLeftTuple(tuple3,
                             context,
                             workingMemory);
        agenda.unstageActivations();
        assertEquals(2,
                     ruleFlowGroup.size());
    }

    @Test
    public void testSequentialAgenda() {
        RuleBaseConfiguration conf = new RuleBaseConfiguration();
        conf.setPhreakEnabled(false);
        conf.setSequential(true);
        InternalRuleBase ruleBase = (InternalRuleBase) RuleBaseFactory.newRuleBase(conf);

        // create the consequence
        final Consequence consequence = new Consequence() {
            private static final long serialVersionUID = 510l;

            public void evaluate(KnowledgeHelper knowledgeHelper,
                                 WorkingMemory workingMemory) {
                // do nothing
            }

            public void readExternal(ObjectInput in) throws IOException,
                    ClassNotFoundException {

            }

            public void writeExternal(ObjectOutput out) throws IOException {

            }

            public String getName() {
                return "default";
            }
        };

        // create a rule for each agendaGroup
        final Rule rule0 = new Rule("test-rule0");
        final RuleTerminalNode node0 = new RuleTerminalNode(3,
                                                            new MockTupleSource(2),
                                                            rule0,
                                                            rule0.getLhs(),
                                                            0,
                                                            buildContext);

        rule0.setConsequence(consequence);
        final PropagationContext context0 = pctxFactory.createPropagationContext(0,
                                                                                 PropagationContext.INSERTION,
                                                                                 rule0,
                                                                                 null,
                                                                                 new DefaultFactHandle());

        final Rule rule1 = new Rule("test-rule1",
                                    "agendaGroup1");
        final RuleTerminalNode node1 = new RuleTerminalNode(5,
                                                            new MockTupleSource(4),
                                                            rule1,
                                                            rule1.getLhs(),
                                                            0,
                                                            buildContext);
        rule1.setConsequence(consequence);
        final PropagationContext context1 = pctxFactory.createPropagationContext(0,
                                                                                 PropagationContext.INSERTION,
                                                                                 rule1,
                                                                                 null,
                                                                                 new DefaultFactHandle());

        final Rule rule2 = new Rule("test-rule2",
                                    "agendaGroup1");
        final RuleTerminalNode node2 = new RuleTerminalNode(7,
                                                            new MockTupleSource(6),
                                                            rule2,
                                                            rule2.getLhs(),
                                                            0,
                                                            buildContext);
        rule2.setConsequence(consequence);
        final PropagationContext context2 = pctxFactory.createPropagationContext(0,
                                                                                 PropagationContext.INSERTION,
                                                                                 rule2,
                                                                                 null,
                                                                                 new DefaultFactHandle());

        final Rule rule3 = new Rule("test-rule3",
                                    "agendaGroup2");
        final RuleTerminalNode node3 = new RuleTerminalNode(9,
                                                            new MockTupleSource(8),
                                                            rule3,
                                                            rule3.getLhs(),
                                                            0,
                                                            buildContext);
        rule3.setConsequence(consequence);
        final PropagationContext context3 = pctxFactory.createPropagationContext(0,
                                                                                 PropagationContext.INSERTION,
                                                                                 rule3,
                                                                                 null,
                                                                                 new DefaultFactHandle());

        final RuleTerminalNodeLeftTuple tuple0 = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(1, "cheese"), node0, true);
        final RuleTerminalNodeLeftTuple tuple2_1 = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(2, "cheese"), node2, true);
        final RuleTerminalNodeLeftTuple tuple2_2 = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(3, "cheese"), node2, true);
        final RuleTerminalNodeLeftTuple tuple3_1 = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(4, "cheese"), node3, true);
        final RuleTerminalNodeLeftTuple tuple3_2 = new RuleTerminalNodeLeftTuple(new DefaultFactHandle(5, "cheese"), node3, true);

        InternalWorkingMemory workingMemory = new AbstractWorkingMemory(0,
                                                                        ruleBase);

        final InternalAgenda agenda = (InternalAgenda) workingMemory.getAgenda();

        final AgendaGroup agendaGroup1 = agenda.getAgendaGroup("agendaGroup1");
        final AgendaGroup agendaGroup2 = agenda.getAgendaGroup("agendaGroup2");

        // focus at this point is MAIN
        assertEquals(0, agenda.focusStackSize());

        node0.assertLeftTuple(tuple0,
                              context0,
                              workingMemory);

        agenda.unstageActivations();

        // check focus is main
        final AgendaGroup main = agenda.getAgendaGroup(AgendaGroup.MAIN);
        assertEquals(agenda.getFocus(), main);
        // check main got the tuple
        assertEquals(1, agenda.getFocus().size());
        node2.assertLeftTuple(tuple2_1, context2, workingMemory);
        agenda.unstageActivations();

        // main is still focus and this tuple went to agendaGroup1
        assertEquals(1, agenda.getFocus().size());

        // check agendaGroup1 still got the tuple
        assertEquals(1, agendaGroup1.size());

        // make sure total agenda size reflects this
        assertEquals(2, agenda.agendaSize());

        // put another one on agendaGroup 1
        node2.assertLeftTuple(tuple2_2,
                              context2,
                              workingMemory);
        agenda.unstageActivations();

        // main is still focus so shouldn't have increased
        assertEquals(1,
                     agenda.getFocus().size());

        // check agendaGroup2 still got the tuple
        assertEquals(2,
                     agendaGroup1.size());

        // make sure total agenda size reflects this
        assertEquals(3,
                     agenda.agendaSize());

        // set the focus to agendaGroup1, note agendaGroup1 has no activations
        agenda.setFocus("agendaGroup1");
        // add agendaGroup2 onto the focus stack
        agenda.setFocus("agendaGroup2");

        // agendaGroup2, the current focus, has no activations
        assertEquals(0,
                     agenda.getFocus().size());

        // add to agendaGroup2
        node3.assertLeftTuple(tuple3_1,
                              context3,
                              workingMemory);
        agenda.unstageActivations();

        assertEquals(1,
                     agenda.getFocus().size());

        node3.assertLeftTuple(tuple3_2,
                              context3,
                              workingMemory);
        agenda.unstageActivations();

        // agendaGroup2 now has 2 activations
        assertEquals(2,
                     agenda.getFocus().size());

        // check totalAgendaSize still works
        assertEquals(5,
                     agenda.agendaSize());

        // ok now lets check that stacks work with fireNextItem
        agenda.fireNextItem(null, 0, -1);

        // agendaGroup2 should still be the current agendaGroup
        assertEquals(agendaGroup2,
                     agenda.getFocus());
        // agendaGroup2 has gone from 2 to one activations
        assertEquals(1,
                     agenda.getFocus().size());
        // check totalAgendaSize has reduced too
        assertEquals(4,
                     agenda.agendaSize());

        // now repeat the process
        agenda.fireNextItem(null, 0, -1);

        // focus is still agendaGroup2, but now its empty
        assertEquals(agendaGroup2,
                     agenda.getFocus());
        assertEquals(0,
                     agenda.getFocus().size());
        assertEquals(3,
                     agenda.agendaSize());

        // repeat fire again
        agenda.fireNextItem(null, 0, -1);

        // agendaGroup2 is empty so it should be popped from the stack making agendaGroup1 the current agendaGroup
        assertEquals(agendaGroup1,
                     agenda.getFocus());
        // agendaGroup1 had 2 activations, now it only has 1
        assertEquals(1,
                     agenda.getFocus().size());
        assertEquals(2,
                     agenda.agendaSize());

        // repeat fire again
        agenda.fireNextItem(null, 0, -1);

        assertEquals(agendaGroup1,
                     agenda.getFocus());
        assertEquals(0,
                     agenda.getFocus().size());
        assertEquals(1,
                     agenda.agendaSize());

        // this last fire is more interesting as it demonstrates that
        // agendaGroup1 on
        // the stack before agendaGroup2 gets skipped as it has no activations
        agenda.fireNextItem(null, 0, -1);

        assertEquals(agenda.getFocus(),
                     main);
        assertEquals(0,
                     agenda.getFocus().size());
        assertEquals(0,
                     agenda.agendaSize());

    }

    @Test
    public void testNullErrorOnGetScheduledActivations() {
        final AbstractWorkingMemory workingMemory = (AbstractWorkingMemory) ruleBase.newStatefulSession();
        try {
            ((InternalAgenda) workingMemory.getAgenda()).getScheduledActivations();
        } catch (NullPointerException e) {
            fail("Exception Should not have been thrown");
        }

    }

}
TOP

Related Classes of org.drools.reteoo.common.AgendaTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.