/*
* Copyright 2015 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.drools.compiler.integrationtests;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Serializable;
import java.io.StringReader;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.drools.compiler.Cheese;
import org.drools.compiler.Cheesery;
import org.drools.compiler.CommonTestMethodBase;
import org.drools.compiler.Order;
import org.drools.compiler.OrderItem;
import org.drools.compiler.OuterClass;
import org.drools.compiler.Person;
import org.drools.compiler.kproject.ReleaseIdImpl;
import org.drools.core.command.runtime.rule.InsertElementsCommand;
import org.drools.core.reteoo.JoinNode;
import org.drools.core.reteoo.LeftTupleSink;
import org.drools.core.reteoo.ObjectSink;
import org.drools.core.reteoo.ObjectTypeNode;
import org.drools.core.reteoo.RightInputAdapterNode;
import org.junit.Test;
import org.kie.api.KieBase;
import org.kie.api.KieBaseConfiguration;
import org.kie.api.KieServices;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.builder.ReleaseId;
import org.kie.api.builder.Results;
import org.kie.api.conf.EventProcessingOption;
import org.kie.api.definition.type.FactType;
import org.kie.api.event.rule.AfterMatchFiredEvent;
import org.kie.api.event.rule.AgendaEventListener;
import org.kie.api.io.ResourceType;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.KieSessionConfiguration;
import org.kie.api.runtime.conf.ClockTypeOption;
import org.kie.api.runtime.rule.AccumulateFunction;
import org.kie.api.runtime.rule.FactHandle;
import org.kie.api.runtime.rule.Match;
import org.kie.api.runtime.rule.QueryResults;
import org.kie.api.runtime.rule.Variable;
import org.kie.api.time.SessionPseudoClock;
import org.kie.internal.KnowledgeBase;
import org.kie.internal.KnowledgeBaseFactory;
import org.kie.internal.builder.KnowledgeBuilder;
import org.kie.internal.builder.KnowledgeBuilderFactory;
import org.kie.internal.builder.conf.PropertySpecificOption;
import org.kie.internal.io.ResourceFactory;
import org.kie.internal.runtime.StatefulKnowledgeSession;
import org.kie.internal.utils.KieHelper;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import static java.util.Arrays.asList;
import static org.hamcrest.CoreMatchers.is;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
public class AccumulateTest extends CommonTestMethodBase {
@Test(timeout = 10000)
public void testAccumulateModify() throws Exception {
// read in the source
KieSession wm = getKieSessionFromResources( "test_AccumulateModify.drl" );
final List<?> results = new ArrayList<Object>();
wm.setGlobal( "results",
results );
final Cheese[] cheese = new Cheese[]{new Cheese( "stilton",
10 ), new Cheese( "stilton",
2 ), new Cheese( "stilton",
5 ), new Cheese( "brie",
15 ), new Cheese( "brie",
16 ), new Cheese( "provolone",
8 )};
final Person bob = new Person( "Bob",
"stilton" );
final FactHandle[] cheeseHandles = new FactHandle[cheese.length];
for ( int i = 0; i < cheese.length; i++ ) {
cheeseHandles[i] = wm.insert( cheese[i] );
}
final org.kie.api.runtime.rule.FactHandle bobHandle = wm.insert( bob );
// ---------------- 1st scenario
wm.fireAllRules();
// no fire, as per rule constraints
assertEquals( 0,
results.size() );
// ---------------- 2nd scenario
final int index = 1;
cheese[index].setPrice( 9 );
wm.update( cheeseHandles[index],
cheese[index] );
wm.fireAllRules();
// 1 fire
assertEquals( 1,
results.size() );
assertEquals( 24,
( (Cheesery) results.get( results.size() - 1 ) ).getTotalAmount() );
// ---------------- 3rd scenario
bob.setLikes( "brie" );
wm.update( bobHandle,
bob );
wm.fireAllRules();
// 2 fires
assertEquals( 2,
results.size() );
assertEquals( 31,
( (Cheesery) results.get( results.size() - 1 ) ).getTotalAmount() );
// ---------------- 4th scenario
wm.delete( cheeseHandles[3] );
wm.fireAllRules();
// should not have fired as per constraint
assertEquals( 2,
results.size() );
}
@Test(timeout = 10000)
public void testAccumulate() throws Exception {
// read in the source
KieSession wm = getKieSessionFromResources( "test_Accumulate.drl" );
final List<?> results = new ArrayList<Object>();
wm.setGlobal( "results",
results );
wm.insert( new Person( "Bob",
"stilton",
20 ) );
wm.insert( new Person( "Mark",
"provolone" ) );
wm.insert( new Cheese( "stilton",
10 ) );
wm.insert( new Cheese( "brie",
5 ) );
wm.insert( new Cheese( "provolone",
150 ) );
wm.fireAllRules();
System.out.println( results );
assertEquals( 5,
results.size() );
assertEquals( 165, results.get( 0 ) );
assertEquals( 10, results.get( 1 ) );
assertEquals( 150, results.get( 2 ) );
assertEquals( 10, results.get( 3 ) );
assertEquals( 210, results.get( 4 ) );
}
@Test(timeout = 10000)
public void testMVELAccumulate() throws Exception {
// read in the source
KieSession wm = getKieSessionFromResources( "test_AccumulateMVEL.drl" );
final List<?> results = new ArrayList<Object>();
wm.setGlobal( "results",
results );
wm.insert( new Person( "Bob",
"stilton",
20 ) );
wm.insert( new Person( "Mark",
"provolone" ) );
wm.insert( new Cheese( "stilton",
10 ) );
wm.insert( new Cheese( "brie",
5 ) );
wm.insert( new Cheese( "provolone",
150 ) );
wm.fireAllRules();
assertEquals( 165, results.get( 0 ) );
assertEquals( 10, results.get( 1 ) );
assertEquals( 150, results.get( 2 ) );
assertEquals( 10, results.get( 3 ) );
assertEquals( 210, results.get( 4 ) );
}
@Test(timeout = 10000)
public void testAccumulateModifyMVEL() throws Exception {
// read in the source
KieSession wm = getKieSessionFromResources( "test_AccumulateModifyMVEL.drl" );
final List<?> results = new ArrayList<Object>();
wm.setGlobal( "results",
results );
final Cheese[] cheese = new Cheese[]{new Cheese( "stilton",
10 ), new Cheese( "stilton",
2 ), new Cheese( "stilton",
5 ), new Cheese( "brie",
15 ), new Cheese( "brie",
16 ), new Cheese( "provolone",
8 )};
final Person bob = new Person( "Bob",
"stilton" );
final FactHandle[] cheeseHandles = new FactHandle[cheese.length];
for ( int i = 0; i < cheese.length; i++ ) {
cheeseHandles[i] = wm.insert( cheese[i] );
}
final org.kie.api.runtime.rule.FactHandle bobHandle = wm.insert( bob );
// ---------------- 1st scenario
wm.fireAllRules();
// no fire, as per rule constraints
assertEquals( 0,
results.size() );
// ---------------- 2nd scenario
final int index = 1;
cheese[index].setPrice( 9 );
wm.update( cheeseHandles[index],
cheese[index] );
wm.fireAllRules();
// 1 fire
assertEquals( 1,
results.size() );
assertEquals( 24,
( (Cheesery) results.get( results.size() - 1 ) ).getTotalAmount() );
// ---------------- 3rd scenario
bob.setLikes( "brie" );
wm.update( bobHandle,
bob );
wm.fireAllRules();
// 2 fires
assertEquals( 2,
results.size() );
assertEquals( 31,
( (Cheesery) results.get( results.size() - 1 ) ).getTotalAmount() );
// ---------------- 4th scenario
wm.delete( cheeseHandles[3] );
wm.fireAllRules();
// should not have fired as per constraint
assertEquals( 2,
results.size() );
}
@Test(timeout = 10000)
public void testAccumulateReverseModify() throws Exception {
// read in the source
KieSession wm = getKieSessionFromResources( "test_AccumulateReverseModify.drl" );
final List<?> results = new ArrayList<Object>();
wm.setGlobal( "results",
results );
final Cheese[] cheese = new Cheese[]{new Cheese( "stilton",
10 ), new Cheese( "stilton",
2 ), new Cheese( "stilton",
5 ), new Cheese( "brie",
15 ), new Cheese( "brie",
16 ), new Cheese( "provolone",
8 )};
final Person bob = new Person( "Bob",
"stilton" );
final FactHandle[] cheeseHandles = new FactHandle[cheese.length];
for ( int i = 0; i < cheese.length; i++ ) {
cheeseHandles[i] = wm.insert( cheese[i] );
}
final org.kie.api.runtime.rule.FactHandle bobHandle = wm.insert( bob );
// ---------------- 1st scenario
wm.fireAllRules();
// no fire, as per rule constraints
assertEquals( 0,
results.size() );
// ---------------- 2nd scenario
final int index = 1;
cheese[index].setPrice( 9 );
wm.update( cheeseHandles[index],
cheese[index] );
wm.fireAllRules();
// 1 fire
assertEquals( 1,
results.size() );
assertEquals( 24,
( (Cheesery) results.get( results.size() - 1 ) ).getTotalAmount() );
// ---------------- 3rd scenario
bob.setLikes( "brie" );
wm.update( bobHandle,
bob );
cheese[3].setPrice( 20 );
wm.update( cheeseHandles[3],
cheese[3] );
wm.fireAllRules();
// 2 fires
assertEquals( 2,
results.size() );
assertEquals( 36,
( (Cheesery) results.get( results.size() - 1 ) ).getTotalAmount() );
// ---------------- 4th scenario
wm.delete( cheeseHandles[3] );
wm.fireAllRules();
// should not have fired as per constraint
assertEquals( 2,
results.size() );
}
@Test(timeout = 10000)
public void testAccumulateReverseModify2() throws Exception {
// read in the source
KieSession wm = getKieSessionFromResources( "test_AccumulateReverseModify2.drl" );
final List<?> results = new ArrayList<Object>();
wm.setGlobal( "results",
results );
final Cheese[] cheese = new Cheese[]{new Cheese( "stilton",
10 ), new Cheese( "stilton",
2 ), new Cheese( "stilton",
5 ), new Cheese( "brie",
15 ), new Cheese( "brie",
16 ), new Cheese( "provolone",
8 )};
final Person bob = new Person( "Bob",
"stilton" );
final FactHandle[] cheeseHandles = new FactHandle[cheese.length];
for ( int i = 0; i < cheese.length; i++ ) {
cheeseHandles[i] = wm.insert( cheese[i] );
}
final FactHandle bobHandle = wm.insert( bob );
// ---------------- 1st scenario
wm.fireAllRules();
// no fire, as per rule constraints
assertEquals( 0,
results.size() );
// ---------------- 2nd scenario
final int index = 1;
cheese[index].setPrice( 9 );
wm.update( cheeseHandles[index],
cheese[index] );
wm.fireAllRules();
// 1 fire
assertEquals( 1,
results.size() );
assertEquals( 24,
( (Number) results.get( results.size() - 1 ) ).intValue() );
// ---------------- 3rd scenario
bob.setLikes( "brie" );
wm.update( bobHandle,
bob );
cheese[3].setPrice( 20 );
wm.update( cheeseHandles[3],
cheese[3] );
wm.fireAllRules();
// 2 fires
assertEquals( 2,
results.size() );
assertEquals( 36,
( (Number) results.get( results.size() - 1 ) ).intValue() );
// ---------------- 4th scenario
wm.delete( cheeseHandles[3] );
wm.fireAllRules();
// should not have fired as per constraint
assertEquals( 2,
results.size() );
}
@Test(timeout = 10000)
public void testAccumulateReverseModifyInsertLogical2() throws Exception {
// read in the source
KieSession wm = getKieSessionFromResources( "test_AccumulateReverseModifyInsertLogical2.drl" );
final List<?> results = new ArrayList<Object>();
wm.setGlobal( "results",
results );
final Cheese[] cheese = new Cheese[]{
new Cheese( "stilton", 10 ),
new Cheese( "stilton", 2 ),
new Cheese( "stilton", 5 ),
new Cheese( "brie", 15 ),
new Cheese( "brie", 16 ),
new Cheese( "provolone", 8 )
};
final Person alice = new Person( "Alice", "brie" );
final Person bob = new Person( "Bob", "stilton" );
final Person carol = new Person( "Carol", "cheddar" );
final Person doug = new Person( "Doug", "stilton" );
final FactHandle[] cheeseHandles = new FactHandle[cheese.length];
for ( int i = 0; i < cheese.length; i++ ) {
cheeseHandles[i] = wm.insert( cheese[i] );
}
final FactHandle aliceHandle = wm.insert( alice );
final FactHandle bobHandle = wm.insert( bob );
// add Carol later
final FactHandle dougHandle = wm.insert( doug ); // should be ignored
// alice = 31, bob = 17, carol = 0, doug = 17
// !alice = 34, !bob = 31, !carol = 65, !doug = 31
wm.fireAllRules();
assertEquals( 31, ( (Number) results.get( results.size() - 1 ) ).intValue() );
// delete stilton=2 ==> bob = 15, doug = 15, !alice = 30, !carol = 61
wm.delete( cheeseHandles[1] );
wm.fireAllRules();
assertEquals( 30, ( (Number) results.get( results.size() - 1 ) ).intValue() );
}
@Test(timeout = 10000)
public void testAccumulateReverseModifyMVEL() throws Exception {
// read in the source
KieSession wm = getKieSessionFromResources( "test_AccumulateReverseModifyMVEL.drl" );
final List<?> results = new ArrayList<Object>();
wm.setGlobal( "results",
results );
final Cheese[] cheese = new Cheese[]{new Cheese( "stilton",
10 ), new Cheese( "stilton",
2 ), new Cheese( "stilton",
5 ), new Cheese( "brie",
15 ), new Cheese( "brie",
16 ), new Cheese( "provolone",
8 )};
final Person bob = new Person( "Bob",
"stilton" );
final FactHandle[] cheeseHandles = new FactHandle[cheese.length];
for ( int i = 0; i < cheese.length; i++ ) {
cheeseHandles[i] = wm.insert( cheese[i] );
}
final FactHandle bobHandle = wm.insert( bob );
// ---------------- 1st scenario
wm.fireAllRules();
// no fire, as per rule constraints
assertEquals( 0,
results.size() );
// ---------------- 2nd scenario
final int index = 1;
cheese[index].setPrice( 9 );
wm.update( cheeseHandles[index],
cheese[index] );
wm.fireAllRules();
// 1 fire
assertEquals( 1,
results.size() );
assertEquals( 24,
( (Cheesery) results.get( results.size() - 1 ) ).getTotalAmount() );
// ---------------- 3rd scenario
bob.setLikes( "brie" );
wm.update( bobHandle,
bob );
wm.fireAllRules();
// 2 fires
assertEquals( 2,
results.size() );
assertEquals( 31,
( (Cheesery) results.get( results.size() - 1 ) ).getTotalAmount() );
// ---------------- 4th scenario
wm.delete( cheeseHandles[3] );
wm.fireAllRules();
// should not have fired as per constraint
assertEquals( 2,
results.size() );
}
@Test(timeout = 10000)
public void testAccumulateReverseModifyMVEL2() throws Exception {
// read in the source
KieSession wm = getKieSessionFromResources( "test_AccumulateReverseModifyMVEL2.drl" );
final List<?> results = new ArrayList<Object>();
wm.setGlobal( "results",
results );
final Cheese[] cheese = new Cheese[]{new Cheese( "stilton",
10 ), new Cheese( "stilton",
2 ), new Cheese( "stilton",
5 ), new Cheese( "brie",
15 ), new Cheese( "brie",
16 ), new Cheese( "provolone",
8 )};
final Person bob = new Person( "Bob",
"stilton" );
final FactHandle[] cheeseHandles = new FactHandle[cheese.length];
for ( int i = 0; i < cheese.length; i++ ) {
cheeseHandles[i] = wm.insert( cheese[i] );
}
final FactHandle bobHandle = wm.insert( bob );
// ---------------- 1st scenario
wm.fireAllRules();
// no fire, as per rule constraints
assertEquals( 0,
results.size() );
// ---------------- 2nd scenario
final int index = 1;
cheese[index].setPrice( 9 );
wm.update( cheeseHandles[index],
cheese[index] );
wm.fireAllRules();
// 1 fire
assertEquals( 1,
results.size() );
assertEquals( 24,
( (Number) results.get( results.size() - 1 ) ).intValue() );
// ---------------- 3rd scenario
bob.setLikes( "brie" );
wm.update( bobHandle,
bob );
wm.fireAllRules();
// 2 fires
assertEquals( 2,
results.size() );
assertEquals( 31,
( (Number) results.get( results.size() - 1 ) ).intValue() );
// ---------------- 4th scenario
wm.delete( cheeseHandles[3] );
wm.fireAllRules();
// should not have fired as per constraint
assertEquals( 2,
results.size() );
}
@Test(timeout = 10000)
public void testAccumulateWithFromChaining() throws Exception {
// read in the source
KieSession wm = getKieSessionFromResources( "test_AccumulateWithFromChaining.drl" );
final List<?> results = new ArrayList<Object>();
wm.setGlobal( "results",
results );
final Cheese[] cheese = new Cheese[]{new Cheese( "stilton",
8 ), new Cheese( "stilton",
10 ), new Cheese( "stilton",
9 ), new Cheese( "brie",
4 ), new Cheese( "brie",
1 ), new Cheese( "provolone",
8 )};
Cheesery cheesery = new Cheesery();
for ( int i = 0; i < cheese.length; i++ ) {
cheesery.addCheese( cheese[i] );
}
FactHandle cheeseryHandle = wm.insert( cheesery );
final Person bob = new Person( "Bob",
"stilton" );
final FactHandle bobHandle = wm.insert( bob );
// ---------------- 1st scenario
wm.fireAllRules();
// one fire, as per rule constraints
assertEquals( 1,
results.size() );
assertEquals( 3,
( (List) results.get( results.size() - 1 ) ).size() );
// ---------------- 2nd scenario
final int index = 1;
cheese[index].setType( "brie" );
wm.update( cheeseryHandle,
cheesery );
wm.fireAllRules();
// no fire
assertEquals( 1,
results.size() );
System.out.println( results );
// ---------------- 3rd scenario
bob.setLikes( "brie" );
wm.update( bobHandle,
bob );
wm.fireAllRules();
// 2 fires
assertEquals( 2,
results.size() );
assertEquals( 3,
( (List) results.get( results.size() - 1 ) ).size() );
// ---------------- 4th scenario
cheesery.getCheeses().remove( cheese[3] );
wm.update( cheeseryHandle,
cheesery );
wm.fireAllRules();
// should not have fired as per constraint
assertEquals( 2,
results.size() );
}
@Test(timeout = 10000)
public void testMVELAccumulate2WM() throws Exception {
// read in the source
KieBase kbase = loadKnowledgeBase( "test_AccumulateMVEL.drl" );
KieSession wm1 = createKieSession( kbase );
final List<?> results1 = new ArrayList<Object>();
wm1.setGlobal( "results",
results1 );
KieSession wm2 = createKieSession( kbase );
final List<?> results2 = new ArrayList<Object>();
wm2.setGlobal( "results",
results2 );
wm1.insert( new Person( "Bob",
"stilton",
20 ) );
wm1.insert( new Person( "Mark",
"provolone" ) );
wm2.insert( new Person( "Bob",
"stilton",
20 ) );
wm2.insert( new Person( "Mark",
"provolone" ) );
wm1.insert( new Cheese( "stilton",
10 ) );
wm1.insert( new Cheese( "brie",
5 ) );
wm2.insert( new Cheese( "stilton",
10 ) );
wm1.insert( new Cheese( "provolone",
150 ) );
wm2.insert( new Cheese( "brie",
5 ) );
wm2.insert( new Cheese( "provolone",
150 ) );
wm1.fireAllRules();
wm2.fireAllRules();
assertEquals( 165, results1.get( 0 ) );
assertEquals( 10, results1.get( 1 ) );
assertEquals( 150, results1.get( 2 ) );
assertEquals( 10, results1.get( 3 ) );
assertEquals( 210, results1.get( 4 ) );
assertEquals( 165, results2.get( 0 ) );
assertEquals( 10, results2.get( 1 ) );
assertEquals( 150, results2.get( 2 ) );
assertEquals( 10, results2.get( 3 ) );
assertEquals( 210, results2.get( 4 ) );
}
@Test(timeout = 10000)
public void testAccumulateInnerClass() throws Exception {
// read in the source
KieSession wm = getKieSessionFromResources( "test_AccumulateInnerClass.drl" );
final List<?> results = new ArrayList<Object>();
wm.setGlobal( "results",
results );
wm.insert( new OuterClass.InnerClass( 10 ) );
wm.insert( new OuterClass.InnerClass( 5 ) );
wm.fireAllRules();
assertEquals( 15, results.get( 0 ) );
}
@Test(timeout = 10000)
public void testAccumulateReturningNull() throws Exception {
// read in the source
KieSession wm = getKieSessionFromResources( "test_AccumulateReturningNull.drl" );
final List<?> results = new ArrayList<Object>();
wm.setGlobal( "results",
results );
wm.insert( new Cheese( "stilton",
10 ) );
}
@Test(timeout = 10000)
public void testAccumulateSumJava() throws Exception {
execTestAccumulateSum( "test_AccumulateSum.drl" );
}
@Test(timeout = 10000)
public void testAccumulateSumMVEL() throws Exception {
execTestAccumulateSum( "test_AccumulateSumMVEL.drl" );
}
@Test(timeout = 10000)
public void testAccumulateMultiPatternWithFunctionJava() throws Exception {
execTestAccumulateSum( "test_AccumulateMultiPatternFunctionJava.drl" );
}
@Test(timeout = 10000)
public void testAccumulateMultiPatternWithFunctionMVEL() throws Exception {
execTestAccumulateSum( "test_AccumulateMultiPatternFunctionMVEL.drl" );
}
@Test(timeout = 10000)
public void testAccumulateCountJava() throws Exception {
execTestAccumulateCount( "test_AccumulateCount.drl" );
}
@Test(timeout = 10000)
public void testAccumulateCountMVEL() throws Exception {
execTestAccumulateCount( "test_AccumulateCountMVEL.drl" );
}
@Test(timeout = 10000)
public void testAccumulateAverageJava() throws Exception {
execTestAccumulateAverage( "test_AccumulateAverage.drl" );
}
@Test(timeout = 10000)
public void testAccumulateAverageMVEL() throws Exception {
execTestAccumulateAverage( "test_AccumulateAverageMVEL.drl" );
}
@Test(timeout = 10000)
public void testAccumulateMinJava() throws Exception {
execTestAccumulateMin( "test_AccumulateMin.drl" );
}
@Test(timeout = 10000)
public void testAccumulateMinMVEL() throws Exception {
execTestAccumulateMin( "test_AccumulateMinMVEL.drl" );
}
@Test(timeout = 10000)
public void testAccumulateMaxJava() throws Exception {
execTestAccumulateMax( "test_AccumulateMax.drl" );
}
@Test(timeout = 10000)
public void testAccumulateMaxMVEL() throws Exception {
execTestAccumulateMax( "test_AccumulateMaxMVEL.drl" );
}
@Test//(timeout = 10000)
public void testAccumulateMultiPatternJava() throws Exception {
execTestAccumulateReverseModifyMultiPattern( "test_AccumulateMultiPattern.drl" );
}
@Test(timeout = 10000)
public void testAccumulateMultiPatternMVEL() throws Exception {
execTestAccumulateReverseModifyMultiPattern( "test_AccumulateMultiPatternMVEL.drl" );
}
@Test(timeout = 10000)
public void testAccumulateCollectListJava() throws Exception {
execTestAccumulateCollectList( "test_AccumulateCollectList.drl" );
}
@Test(timeout = 10000)
public void testAccumulateCollectListMVEL() throws Exception {
execTestAccumulateCollectList( "test_AccumulateCollectListMVEL.drl" );
}
@Test(timeout = 10000)
public void testAccumulateCollectSetJava() throws Exception {
execTestAccumulateCollectSet( "test_AccumulateCollectSet.drl" );
}
@Test(timeout = 10000)
public void testAccumulateCollectSetMVEL() throws Exception {
execTestAccumulateCollectSet( "test_AccumulateCollectSetMVEL.drl" );
}
@Test(timeout = 10000)
public void testAccumulateMultipleFunctionsJava() throws Exception {
execTestAccumulateMultipleFunctions( "test_AccumulateMultipleFunctions.drl" );
}
@Test(timeout = 10000)
public void testAccumulateMultipleFunctionsMVEL() throws Exception {
execTestAccumulateMultipleFunctions( "test_AccumulateMultipleFunctionsMVEL.drl" );
}
@Test(timeout = 10000)
public void testAccumulateMultipleFunctionsConstraint() throws Exception {
execTestAccumulateMultipleFunctionsConstraint( "test_AccumulateMultipleFunctionsConstraint.drl" );
}
@Test(timeout = 10000)
public void testAccumulateWithAndOrCombinations() throws Exception {
// JBRULES-3482
// once this compils, update it to actually assert on correct outputs.
String rule = "package org.drools.compiler.test;\n" +
"import org.drools.compiler.Cheese;\n" +
"import org.drools.compiler.Person;\n" +
"rule \"Class cast causer\"\n" +
" when\n" +
" $person : Person( $likes : likes )\n" +
" $total : Number() from accumulate( $p : Person(likes != $likes, $l : likes) and $c : Cheese( type == $l ),\n" +
" min($c.getPrice()) )\n" +
" ($p2 : Person(name == 'nobody') or $p2 : Person(name == 'Doug'))\n" +
" then\n" +
" System.out.println($p2.getName());\n" +
"end\n";
// read in the source
KnowledgeBase kbase = loadKnowledgeBaseFromString( rule );
StatefulKnowledgeSession wm = createKnowledgeSession( kbase );
wm.insert( new Cheese( "stilton", 10 ) );
wm.insert( new Person( "Alice", "brie" ) );
wm.insert( new Person( "Bob", "stilton" ) );
}
@Test//(timeout = 10000)
public void testAccumulateWithSameSubnetwork() throws Exception {
String rule = "package org.drools.compiler.test;\n" +
"import org.drools.compiler.Cheese;\n" +
"import org.drools.compiler.Person;\n" +
"global java.util.List list; \n" +
"rule r1 salience 100 \n" +
" when\n" +
" $person : Person( name == 'Alice', $likes : likes )\n" +
" $total : Number() from accumulate( $p : Person(likes != $likes, $l : likes) and $c : Cheese( type == $l ),\n" +
" min($c.getPrice()) )\n" +
" then\n" +
" list.add( 'r1' + ':' + $total);\n" +
"end\n" +
"rule r2 \n" +
" when\n" +
" $person : Person( name == 'Alice', $likes : likes )\n" +
" $total : Number() from accumulate( $p : Person(likes != $likes, $l : likes) and $c : Cheese( type == $l ),\n" +
" max($c.getPrice()) )\n" +
" then\n" +
" list.add( 'r2' + ':' + $total);\n" +
"end\n" +
"";
// read in the source
KnowledgeBase kbase = loadKnowledgeBaseFromString( rule );
StatefulKnowledgeSession wm = createKnowledgeSession( kbase );
List list = new ArrayList();
wm.setGlobal( "list", list );
// Check the network formation, to ensure the RiaNode is shared.
ObjectTypeNode cheeseOtn = LinkingTest.getObjectTypeNode( kbase, Cheese.class );
ObjectSink[] oSinks = cheeseOtn.getObjectSinkPropagator().getSinks();
assertEquals( 1, oSinks.length );
JoinNode cheeseJoin = (JoinNode) oSinks[0];
LeftTupleSink[] ltSinks = cheeseJoin.getSinkPropagator().getSinks();
assertEquals( 1, ltSinks.length );
RightInputAdapterNode rian = (RightInputAdapterNode) ltSinks[0];
assertEquals( 2, rian.getObjectSinkPropagator().size() ); // RiaNode is shared, if this has two outputs
wm.insert( new Cheese( "stilton", 10 ) );
wm.insert( new Person( "Alice", "brie" ) );
wm.insert( new Person( "Bob", "stilton" ) );
wm.fireAllRules();
assertEquals( 2, list.size() );
assertEquals( "r1:10", list.get( 0 ) );
assertEquals( "r2:10", list.get( 1 ) );
}
public void execTestAccumulateSum( String fileName ) throws Exception {
// read in the source
KieSession session = getKieSessionFromResources( fileName );
DataSet data = new DataSet();
data.results = new ArrayList<Object>();
session.setGlobal( "results",
data.results );
data.cheese = new Cheese[]{new Cheese( "stilton",
8,
0 ), new Cheese( "stilton",
10,
1 ), new Cheese( "stilton",
9,
2 ), new Cheese( "brie",
11,
3 ), new Cheese( "brie",
4,
4 ), new Cheese( "provolone",
8,
5 )};
data.bob = new Person( "Bob",
"stilton" );
data.cheeseHandles = new FactHandle[data.cheese.length];
for ( int i = 0; i < data.cheese.length; i++ ) {
data.cheeseHandles[i] = session.insert( data.cheese[i] );
}
data.bobHandle = session.insert( data.bob );
// ---------------- 1st scenario
session.fireAllRules();
assertEquals( 1,
data.results.size() );
assertEquals( 27,
( (Number) data.results.get( data.results.size() - 1 ) ).intValue() );
session = SerializationHelper.getSerialisedStatefulKnowledgeSession( session,
true );
updateReferences( session,
data );
// ---------------- 2nd scenario
final int index = 1;
data.cheese[index].setPrice( 3 );
session.update( data.cheeseHandles[index],
data.cheese[index] );
int count = session.fireAllRules();
assertEquals( 1, count );
assertEquals( 2,
data.results.size() );
assertEquals( 20,
( (Number) data.results.get( data.results.size() - 1 ) ).intValue() );
// ---------------- 3rd scenario
data.bob.setLikes( "brie" );
session.update( data.bobHandle,
data.bob );
session.fireAllRules();
assertEquals( 3,
data.results.size() );
assertEquals( 15,
( (Number) data.results.get( data.results.size() - 1 ) ).intValue() );
// ---------------- 4th scenario
session.delete( data.cheeseHandles[3] );
session.fireAllRules();
// should not have fired as per constraint
assertEquals( 3,
data.results.size() );
}
private void updateReferences( final KieSession session,
final DataSet data ) {
data.results = (List<?>) session.getGlobal( "results" );
for ( Iterator<?> it = session.getObjects().iterator(); it.hasNext(); ) {
Object next = it.next();
if ( next instanceof Cheese ) {
Cheese c = (Cheese) next;
data.cheese[c.getOldPrice()] = c;
data.cheeseHandles[c.getOldPrice()] = session.getFactHandle( c );
assertNotNull( data.cheeseHandles[c.getOldPrice()] );
} else if ( next instanceof Person ) {
data.bob = (Person) next;
data.bobHandle = session.getFactHandle( data.bob );
}
}
}
public void execTestAccumulateCount( String fileName ) throws Exception {
// read in the source
KieSession wm = getKieSessionFromResources( fileName );
final List<?> results = new ArrayList<Object>();
wm.setGlobal( "results",
results );
final Cheese[] cheese = new Cheese[]{new Cheese( "stilton",
8 ), new Cheese( "stilton",
10 ), new Cheese( "stilton",
9 ), new Cheese( "brie",
4 ), new Cheese( "brie",
1 ), new Cheese( "provolone",
8 )};
final Person bob = new Person( "Bob",
"stilton" );
final FactHandle[] cheeseHandles = new FactHandle[cheese.length];
for ( int i = 0; i < cheese.length; i++ ) {
cheeseHandles[i] = wm.insert( cheese[i] );
}
final FactHandle bobHandle = wm.insert( bob );
// ---------------- 1st scenario
wm.fireAllRules();
// no fire, as per rule constraints
assertEquals( 1,
results.size() );
assertEquals( 3,
( (Number) results.get( results.size() - 1 ) ).intValue() );
// ---------------- 2nd scenario
final int index = 1;
cheese[index].setPrice( 3 );
wm.update( cheeseHandles[index],
cheese[index] );
wm.fireAllRules();
// 1 fire
assertEquals( 2,
results.size() );
assertEquals( 3,
( (Number) results.get( results.size() - 1 ) ).intValue() );
// ---------------- 3rd scenario
bob.setLikes( "brie" );
wm.update( bobHandle,
bob );
wm.fireAllRules();
// 2 fires
assertEquals( 3,
results.size() );
assertEquals( 2,
( (Number) results.get( results.size() - 1 ) ).intValue() );
// ---------------- 4th scenario
wm.delete( cheeseHandles[3] );
wm.fireAllRules();
// should not have fired as per constraint
assertEquals( 3,
results.size() );
}
public void execTestAccumulateAverage( String fileName ) throws Exception {
// read in the source
KieSession wm = getKieSessionFromResources( fileName );
final List<?> results = new ArrayList<Object>();
wm.setGlobal( "results",
results );
final Cheese[] cheese = new Cheese[]{new Cheese( "stilton",
10 ), new Cheese( "stilton",
2 ), new Cheese( "stilton",
11 ), new Cheese( "brie",
15 ), new Cheese( "brie",
17 ), new Cheese( "provolone",
8 )};
final Person bob = new Person( "Bob",
"stilton" );
final FactHandle[] cheeseHandles = new FactHandle[cheese.length];
for ( int i = 0; i < cheese.length; i++ ) {
cheeseHandles[i] = wm.insert( cheese[i] );
}
final FactHandle bobHandle = wm.insert( bob );
// ---------------- 1st scenario
wm.fireAllRules();
// no fire, as per rule constraints
assertEquals( 0,
results.size() );
// ---------------- 2nd scenario
final int index = 1;
cheese[index].setPrice( 9 );
wm.update( cheeseHandles[index],
cheese[index] );
wm.fireAllRules();
// 1 fire
assertEquals( 1,
results.size() );
assertEquals( 10,
( (Number) results.get( results.size() - 1 ) ).intValue() );
// ---------------- 3rd scenario
bob.setLikes( "brie" );
wm.update( bobHandle,
bob );
wm.fireAllRules();
// 2 fires
assertEquals( 2,
results.size() );
assertEquals( 16,
( (Number) results.get( results.size() - 1 ) ).intValue() );
// ---------------- 4th scenario
wm.delete( cheeseHandles[3] );
wm.delete( cheeseHandles[4] );
wm.fireAllRules();
// should not have fired as per constraint
assertEquals( 2,
results.size() );
}
public void execTestAccumulateMin( String fileName ) throws Exception {
// read in the source
KieSession wm = getKieSessionFromResources( fileName );
final List<?> results = new ArrayList<Object>();
wm.setGlobal( "results",
results );
final Cheese[] cheese = new Cheese[]{new Cheese( "stilton",
8 ), new Cheese( "stilton",
10 ), new Cheese( "stilton",
9 ), new Cheese( "brie",
4 ), new Cheese( "brie",
1 ), new Cheese( "provolone",
8 )};
final Person bob = new Person( "Bob",
"stilton" );
final FactHandle[] cheeseHandles = new FactHandle[cheese.length];
for ( int i = 0; i < cheese.length; i++ ) {
cheeseHandles[i] = wm.insert( cheese[i] );
}
final FactHandle bobHandle = wm.insert( bob );
// ---------------- 1st scenario
wm.fireAllRules();
// no fire, as per rule constraints
assertEquals( 0,
results.size() );
// ---------------- 2nd scenario
final int index = 1;
cheese[index].setPrice( 3 );
wm.update( cheeseHandles[index],
cheese[index] );
wm.fireAllRules();
// 1 fire
assertEquals( 1,
results.size() );
assertEquals( 3,
( (Number) results.get( results.size() - 1 ) ).intValue() );
// ---------------- 3rd scenario
bob.setLikes( "brie" );
wm.update( bobHandle,
bob );
wm.fireAllRules();
// 2 fires
assertEquals( 2,
results.size() );
assertEquals( 1,
( (Number) results.get( results.size() - 1 ) ).intValue() );
// ---------------- 4th scenario
wm.delete( cheeseHandles[3] );
wm.delete( cheeseHandles[4] );
wm.fireAllRules();
// should not have fired as per constraint
assertEquals( 2,
results.size() );
}
public void execTestAccumulateMax( String fileName ) throws Exception {
// read in the source
KieSession wm = getKieSessionFromResources( fileName );
final List<?> results = new ArrayList<Object>();
wm.setGlobal( "results",
results );
final Cheese[] cheese = new Cheese[]{new Cheese( "stilton",
4 ), new Cheese( "stilton",
2 ), new Cheese( "stilton",
3 ), new Cheese( "brie",
15 ), new Cheese( "brie",
17 ), new Cheese( "provolone",
8 )};
final Person bob = new Person( "Bob",
"stilton" );
final FactHandle[] cheeseHandles = new FactHandle[cheese.length];
for ( int i = 0; i < cheese.length; i++ ) {
cheeseHandles[i] = wm.insert( cheese[i] );
}
final FactHandle bobHandle = wm.insert( bob );
// ---------------- 1st scenario
wm.fireAllRules();
// no fire, as per rule constraints
assertEquals( 0,
results.size() );
// ---------------- 2nd scenario
final int index = 1;
cheese[index].setPrice( 9 );
wm.update( cheeseHandles[index],
cheese[index] );
wm.fireAllRules();
// 1 fire
assertEquals( 1,
results.size() );
assertEquals( 9,
( (Number) results.get( results.size() - 1 ) ).intValue() );
// ---------------- 3rd scenario
bob.setLikes( "brie" );
wm.update( bobHandle,
bob );
wm.fireAllRules();
// 2 fires
assertEquals( 2,
results.size() );
assertEquals( 17,
( (Number) results.get( results.size() - 1 ) ).intValue() );
// ---------------- 4th scenario
wm.delete( cheeseHandles[3] );
wm.delete( cheeseHandles[4] );
wm.fireAllRules();
// should not have fired as per constraint
assertEquals( 2,
results.size() );
}
public void execTestAccumulateCollectList( String fileName ) throws Exception {
// read in the source
KieSession wm = getKieSessionFromResources( fileName );
final List<?> results = new ArrayList<Object>();
wm.setGlobal( "results",
results );
final Cheese[] cheese = new Cheese[]{new Cheese( "stilton",
4 ), new Cheese( "stilton",
2 ), new Cheese( "stilton",
3 ), new Cheese( "brie",
15 ), new Cheese( "brie",
17 ), new Cheese( "provolone",
8 )};
final FactHandle[] cheeseHandles = new FactHandle[cheese.length];
for ( int i = 0; i < cheese.length; i++ ) {
cheeseHandles[i] = wm.insert( cheese[i] );
}
// ---------------- 1st scenario
wm.fireAllRules();
assertEquals( 1,
results.size() );
assertEquals( 6,
( (List) results.get( results.size() - 1 ) ).size() );
// ---------------- 2nd scenario
final int index = 1;
cheese[index].setPrice( 9 );
wm.update( cheeseHandles[index],
cheese[index] );
wm.fireAllRules();
// fire again
assertEquals( 2,
results.size() );
assertEquals( 6,
( (List) results.get( results.size() - 1 ) ).size() );
// ---------------- 3rd scenario
wm.delete( cheeseHandles[3] );
wm.delete( cheeseHandles[4] );
wm.fireAllRules();
// should not have fired as per constraint
assertEquals( 2,
results.size() );
}
public void execTestAccumulateCollectSet( String fileName ) throws Exception {
// read in the source
KieSession wm = getKieSessionFromResources( fileName );
final List<?> results = new ArrayList<Object>();
wm.setGlobal( "results",
results );
final Cheese[] cheese = new Cheese[]{new Cheese( "stilton",
4 ), new Cheese( "stilton",
2 ), new Cheese( "stilton",
3 ), new Cheese( "brie",
15 ), new Cheese( "brie",
17 ), new Cheese( "provolone",
8 )};
final FactHandle[] cheeseHandles = new FactHandle[cheese.length];
for ( int i = 0; i < cheese.length; i++ ) {
cheeseHandles[i] = wm.insert( cheese[i] );
}
// ---------------- 1st scenario
wm.fireAllRules();
assertEquals( 1,
results.size() );
assertEquals( 3,
( (Set) results.get( results.size() - 1 ) ).size() );
// ---------------- 2nd scenario
final int index = 1;
cheese[index].setPrice( 9 );
wm.update( cheeseHandles[index],
cheese[index] );
wm.fireAllRules();
// fire again
assertEquals( 2,
results.size() );
assertEquals( 3,
( (Set) results.get( results.size() - 1 ) ).size() );
// ---------------- 3rd scenario
wm.delete( cheeseHandles[3] );
wm.fireAllRules();
// fire again
assertEquals( 3,
results.size() );
assertEquals( 3,
( (Set) results.get( results.size() - 1 ) ).size() );
// ---------------- 4rd scenario
wm.delete( cheeseHandles[4] );
wm.fireAllRules();
// should not have fired as per constraint
assertEquals( 3,
results.size() );
}
public void execTestAccumulateReverseModifyMultiPattern( String fileName ) throws Exception {
// read in the source
KieSession wm = getKieSessionFromResources( fileName );
final List<?> results = new ArrayList<Object>();
wm.setGlobal( "results",
results );
final Cheese[] cheese = new Cheese[]{ new Cheese( "stilton", 10 ),
new Cheese( "stilton", 2 ),
new Cheese( "stilton", 5 ),
new Cheese( "brie", 15 ),
new Cheese( "brie", 16 ),
new Cheese( "provolone", 8 ) };
final Person bob = new Person( "Bob",
"stilton" );
final Person mark = new Person( "Mark",
"provolone" );
final FactHandle[] cheeseHandles = new FactHandle[cheese.length];
for ( int i = 0; i < cheese.length; i++ ) {
cheeseHandles[i] = wm.insert( cheese[i] );
}
final FactHandle bobHandle = wm.insert( bob );
final FactHandle markHandle = wm.insert( mark );
// ---------------- 1st scenario
wm.fireAllRules();
// no fire, as per rule constraints
assertEquals( 0,
results.size() );
// ---------------- 2nd scenario
final int index = 1;
cheese[index].setPrice( 9 );
wm.update( cheeseHandles[index],
cheese[index] );
wm.fireAllRules();
// 1 fire
assertEquals( 1,
results.size() );
assertEquals( 32,
( (Cheesery) results.get( results.size() - 1 ) ).getTotalAmount() );
// ---------------- 3rd scenario
bob.setLikes( "brie" );
wm.update( bobHandle,
bob );
wm.fireAllRules();
// 2 fires
assertEquals( 2,
results.size() );
assertEquals( 39,
( (Cheesery) results.get( results.size() - 1 ) ).getTotalAmount() );
// ---------------- 4th scenario
wm.delete( cheeseHandles[3] );
wm.fireAllRules();
// should not have fired as per constraint
assertEquals( 2,
results.size() );
}
@Test(timeout = 10000)
public void testAccumulateWithPreviouslyBoundVariables() throws Exception {
// read in the source
KieSession wm = getKieSessionFromResources( "test_AccumulatePreviousBinds.drl" );
final List<?> results = new ArrayList<Object>();
wm.setGlobal( "results",
results );
wm.insert( new Cheese( "stilton",
10 ) );
wm.insert( new Cheese( "brie",
5 ) );
wm.insert( new Cheese( "provolone",
150 ) );
wm.insert( new Cheese( "brie",
20 ) );
wm.fireAllRules();
assertEquals( 1,
results.size() );
assertEquals( 45,
results.get( 0 ) );
}
@Test(timeout = 10000)
public void testAccumulateMVELWithModify() throws Exception {
// read in the source
KieSession wm = getKieSessionFromResources( "test_AccumulateMVELwithModify.drl" );
final List<Number> results = new ArrayList<Number>();
wm.setGlobal( "results",
results );
Order order = new Order( 1,
"Bob" );
OrderItem item1 = new OrderItem( order,
1,
"maquilage",
1,
10 );
OrderItem item2 = new OrderItem( order,
2,
"perfume",
1,
5 );
order.addItem( item1 );
order.addItem( item2 );
wm.insert( order );
wm.insert( item1 );
wm.insert( item2 );
wm.fireAllRules();
assertEquals( 1,
results.size() );
assertEquals( 15,
results.get( 0 ).intValue() );
assertEquals( 15.0,
order.getTotal(),
0.0 );
}
@Test(timeout = 10000)
public void testAccumulateGlobals() throws Exception {
// read in the source
KieSession wm = getKieSessionFromResources( "test_AccumulateGlobals.drl" );
final List<?> results = new ArrayList<Object>();
wm.setGlobal( "results",
results );
wm.setGlobal( "globalValue",
50 );
wm.insert( new Cheese( "stilton",
10 ) );
wm.insert( new Cheese( "brie",
5 ) );
wm.insert( new Cheese( "provolone",
150 ) );
wm.insert( new Cheese( "brie",
20 ) );
wm.fireAllRules();
assertEquals( 1,
results.size() );
assertEquals( 100,
results.get( 0 ) );
}
@Test(timeout = 10000)
public void testAccumulateNonExistingFunction() throws Exception {
final KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add( ResourceFactory.newClassPathResource( "test_NonExistingAccumulateFunction.drl",
getClass() ),
ResourceType.DRL );
// should report a proper error, not raise an exception
assertTrue( "It must report a proper error when trying to use a non-registered funcion",
kbuilder.hasErrors() );
assertTrue( kbuilder.getErrors().toString().contains( "Unknown accumulate function: 'nonExistingFunction' on rule 'Accumulate non existing function - Java'." ) );
assertTrue( kbuilder.getErrors().toString().contains( "Unknown accumulate function: 'nonExistingFunction' on rule 'Accumulate non existing function - MVEL'." ) );
}
@Test(timeout = 10000)
public void testAccumulateZeroParams() {
String rule = "global java.util.List list;\n" +
"rule fromIt\n" +
"when\n" +
" Number( $c: intValue ) from accumulate( Integer(), count( ) )\n" +
"then\n" +
" list.add( $c );\n" +
"end";
KnowledgeBase kbase = loadKnowledgeBaseFromString( rule );
StatefulKnowledgeSession ksession = createKnowledgeSession( kbase );
List list = new ArrayList();
ksession.setGlobal( "list", list );
ksession.insert( new Integer( 1 ) );
ksession.insert( new Integer( 2 ) );
ksession.insert( new Integer( 3 ) );
ksession.fireAllRules();
assertEquals( 1, list.size() );
assertEquals( 3, list.get( 0 ) );
}
public void execTestAccumulateMultipleFunctions( String fileName ) throws Exception {
KieSession ksession = getKieSessionFromResources( fileName );
AgendaEventListener ael = mock( AgendaEventListener.class );
ksession.addEventListener( ael );
final Cheese[] cheese = new Cheese[]{new Cheese( "stilton",
10 ),
new Cheese( "stilton",
3 ),
new Cheese( "stilton",
5 ),
new Cheese( "brie",
15 ),
new Cheese( "brie",
17 ),
new Cheese( "provolone",
8 )};
final Person bob = new Person( "Bob",
"stilton" );
final FactHandle[] cheeseHandles = new FactHandle[cheese.length];
for ( int i = 0; i < cheese.length; i++ ) {
cheeseHandles[i] = (FactHandle) ksession.insert( cheese[i] );
}
final FactHandle bobHandle = (FactHandle) ksession.insert( bob );
// ---------------- 1st scenario
ksession.fireAllRules();
ArgumentCaptor<AfterMatchFiredEvent> cap = ArgumentCaptor.forClass( AfterMatchFiredEvent.class );
Mockito.verify( ael ).afterMatchFired( cap.capture() );
Match activation = cap.getValue().getMatch();
assertThat( ( (Number) activation.getDeclarationValue( "$sum" ) ).intValue(),
is( 18 ) );
assertThat( ( (Number) activation.getDeclarationValue( "$min" ) ).intValue(),
is( 3 ) );
assertThat( ( (Number) activation.getDeclarationValue( "$avg" ) ).intValue(),
is( 6 ) );
Mockito.reset( ael );
// ---------------- 2nd scenario
final int index = 1;
cheese[index].setPrice( 9 );
ksession.update( cheeseHandles[index],
cheese[index] );
ksession.fireAllRules();
Mockito.verify( ael ).afterMatchFired( cap.capture() );
activation = cap.getValue().getMatch();
assertThat( ( (Number) activation.getDeclarationValue( "$sum" ) ).intValue(),
is( 24 ) );
assertThat( ( (Number) activation.getDeclarationValue( "$min" ) ).intValue(),
is( 5 ) );
assertThat( ( (Number) activation.getDeclarationValue( "$avg" ) ).intValue(),
is( 8 ) );
Mockito.reset( ael );
// ---------------- 3rd scenario
bob.setLikes( "brie" );
ksession.update( bobHandle,
bob );
ksession.fireAllRules();
Mockito.verify( ael ).afterMatchFired( cap.capture() );
activation = cap.getValue().getMatch();
assertThat( ( (Number) activation.getDeclarationValue( "$sum" ) ).intValue(),
is( 32 ) );
assertThat( ( (Number) activation.getDeclarationValue( "$min" ) ).intValue(),
is( 15 ) );
assertThat( ( (Number) activation.getDeclarationValue( "$avg" ) ).intValue(),
is( 16 ) );
Mockito.reset( ael );
// ---------------- 4th scenario
ksession.delete( cheeseHandles[3] );
ksession.fireAllRules();
Mockito.verify( ael ).afterMatchFired( cap.capture() );
activation = cap.getValue().getMatch();
assertThat( ( (Number) activation.getDeclarationValue( "$sum" ) ).intValue(),
is( 17 ) );
assertThat( ( (Number) activation.getDeclarationValue( "$min" ) ).intValue(),
is( 17 ) );
assertThat( ( (Number) activation.getDeclarationValue( "$avg" ) ).intValue(),
is( 17 ) );
}
public void execTestAccumulateMultipleFunctionsConstraint( String fileName ) throws Exception {
KieSession ksession = getKieSessionFromResources( fileName );
AgendaEventListener ael = mock( AgendaEventListener.class );
ksession.addEventListener( ael );
final Cheese[] cheese = new Cheese[]{new Cheese( "stilton",
10 ),
new Cheese( "stilton",
3 ),
new Cheese( "stilton",
5 ),
new Cheese( "brie",
3 ),
new Cheese( "brie",
17 ),
new Cheese( "provolone",
8 )};
final Person bob = new Person( "Bob",
"stilton" );
final FactHandle[] cheeseHandles = new FactHandle[cheese.length];
for ( int i = 0; i < cheese.length; i++ ) {
cheeseHandles[i] = (FactHandle) ksession.insert( cheese[i] );
}
final FactHandle bobHandle = (FactHandle) ksession.insert( bob );
// ---------------- 1st scenario
ksession.fireAllRules();
ArgumentCaptor<AfterMatchFiredEvent> cap = ArgumentCaptor.forClass( AfterMatchFiredEvent.class );
Mockito.verify( ael ).afterMatchFired( cap.capture() );
Match activation = cap.getValue().getMatch();
assertThat( ( (Number) activation.getDeclarationValue( "$sum" ) ).intValue(),
is( 18 ) );
assertThat( ( (Number) activation.getDeclarationValue( "$min" ) ).intValue(),
is( 3 ) );
assertThat( ( (Number) activation.getDeclarationValue( "$avg" ) ).intValue(),
is( 6 ) );
Mockito.reset( ael );
// ---------------- 2nd scenario
final int index = 1;
cheese[index].setPrice( 9 );
ksession.update( cheeseHandles[index],
cheese[index] );
ksession.fireAllRules();
Mockito.verify( ael, Mockito.never() ).afterMatchFired( Mockito.any( AfterMatchFiredEvent.class ) );
Mockito.reset( ael );
// ---------------- 3rd scenario
bob.setLikes( "brie" );
ksession.update( bobHandle,
bob );
ksession.fireAllRules();
Mockito.verify( ael ).afterMatchFired( cap.capture() );
activation = cap.getValue().getMatch();
assertThat( ( (Number) activation.getDeclarationValue( "$sum" ) ).intValue(),
is( 20 ) );
assertThat( ( (Number) activation.getDeclarationValue( "$min" ) ).intValue(),
is( 3 ) );
assertThat( ( (Number) activation.getDeclarationValue( "$avg" ) ).intValue(),
is( 10 ) );
ksession.dispose();
}
public static class DataSet {
public Cheese[] cheese;
public FactHandle[] cheeseHandles;
public Person bob;
public FactHandle bobHandle;
public List<?> results;
}
@Test(timeout = 10000)
public void testAccumulateMinMax() throws Exception {
String drl = "package org.drools.compiler.test \n" +
"import org.drools.compiler.Cheese \n" +
"global java.util.List results \n " +
"rule minMax \n" +
"when \n" +
" accumulate( Cheese( $p: price ), $min: min($p), $max: max($p) ) \n" +
"then \n" +
" results.add($min); results.add($max); \n" +
"end \n";
KnowledgeBase kbase = loadKnowledgeBaseFromString( drl );
StatefulKnowledgeSession ksession = createKnowledgeSession( kbase );
final List<Number> results = new ArrayList<Number>();
ksession.setGlobal( "results",
results );
final Cheese[] cheese = new Cheese[]{new Cheese( "Emmentaler",
4 ),
new Cheese( "Appenzeller",
6 ),
new Cheese( "Greyerzer",
2 ),
new Cheese( "Raclette",
3 ),
new Cheese( "Olmützer Quargel",
15 ),
new Cheese( "Brie",
17 ),
new Cheese( "Dolcelatte",
8 )};
for ( Cheese aCheese : cheese ) {
ksession.insert( aCheese );
}
// ---------------- 1st scenario
ksession.fireAllRules();
assertEquals( 2,
results.size() );
assertEquals( results.get( 0 ).intValue(),
2 );
assertEquals( results.get( 1 ).intValue(),
17 );
}
@Test(timeout = 10000)
public void testAccumulateCE() throws Exception {
String drl = "package org.drools.compiler\n" +
"global java.util.List results\n" +
"rule \"ocount\"\n" +
"when\n" +
" accumulate( Cheese(), $c: count(1) )\n" +
"then\n" +
" results.add( $c + \" facts\" );\n" +
"end\n";
KnowledgeBase kbase = loadKnowledgeBaseFromString( drl );
StatefulKnowledgeSession ksession = createKnowledgeSession( kbase );
final List<String> results = new ArrayList<String>();
ksession.setGlobal( "results",
results );
final Cheese[] cheese = new Cheese[]{new Cheese( "Emmentaler",
4 ),
new Cheese( "Appenzeller",
6 ),
new Cheese( "Greyerzer",
2 ),
new Cheese( "Raclette",
3 ),
new Cheese( "Olmützer Quargel",
15 ),
new Cheese( "Brie",
17 ),
new Cheese( "Dolcelatte",
8 )};
for ( Cheese aCheese : cheese ) {
ksession.insert( aCheese );
}
// ---------------- 1st scenario
ksession.fireAllRules();
assertEquals( 1,
results.size() );
assertEquals( "7 facts",
results.get( 0 ) );
}
@Test(timeout = 10000)
public void testAccumulateAndRetract() {
String drl = "package org.drools.compiler;\n" +
"\n" +
"import java.util.ArrayList;\n" +
"\n" +
"global ArrayList list;\n" +
"\n" +
"declare Holder\n" +
" list : ArrayList\n" +
"end\n" +
"\n" +
"rule \"Init\"\n" +
"when\n" +
" $l : ArrayList()\n" +
"then\n" +
" insert( new Holder($l) );\n" +
"end\n" +
"\n" +
"rule \"axx\"\n" +
"when\n" +
" $h : Holder( $l : list )\n" +
" $n : Long() from accumulate (\n" +
" $b : String( ) from $l;\n" +
" count($b))\n" +
"then\n" +
" System.out.println($n);\n" +
" list.add($n);\n" +
"end\n" +
"\n" +
"rule \"clean\"\n" +
"salience -10\n" +
"when\n" +
" $h : Holder()\n" +
"then\n" +
" retract($h);\n" +
"end" +
"\n";
KieSession ks = getKieSessionFromContentStrings( drl );
ArrayList resList = new ArrayList();
ks.setGlobal( "list", resList );
ArrayList<String> list = new ArrayList<String>();
list.add( "x" );
list.add( "y" );
list.add( "z" );
ks.insert( list );
ks.fireAllRules();
assertEquals( 3L, resList.get( 0 ) );
}
@Test(timeout = 10000)
public void testAccumulateWithNull() {
String drl = "rule foo\n" +
"when\n" +
"Object() from accumulate( Object(),\n" +
"init( Object res = null; )\n" +
"action( res = null; )\n" +
"result( res ) )\n" +
"then\n" +
"end";
KieSession ksession = getKieSessionFromContentStrings( drl );
ksession.fireAllRules();
ksession.dispose();
}
public static class MyObj {
public static class NestedObj {
public long value;
public NestedObj( long value ) {
this.value = value;
}
}
private final NestedObj nestedObj;
public MyObj( long value ) {
nestedObj = new NestedObj( value );
}
public NestedObj getNestedObj() {
return nestedObj;
}
}
@Test(timeout = 10000)
public void testAccumulateWithBoundExpression() {
String drl = "package org.drools.compiler;\n" +
"import " + AccumulateTest.MyObj.class.getCanonicalName() + ";\n" +
"global java.util.List results\n" +
"rule init\n" +
" when\n" +
" then\n" +
" insert( new MyObj(5) );\n" +
" insert( new MyObj(4) );\n" +
"end\n" +
"rule foo\n" +
" salience -10\n" +
" when\n" +
" $n : Number() from accumulate( MyObj( $val : nestedObj.value ),\n" +
" sum( $val ) )\n" +
" then\n" +
" System.out.println($n);\n" +
" results.add($n);\n" +
"end";
KieBase kbase = loadKnowledgeBaseFromString( drl );
KieSession ksession = kbase.newKieSession();
final List<Number> results = new ArrayList<Number>();
ksession.setGlobal( "results",
results );
ksession.fireAllRules();
ksession.dispose();
assertEquals( 1,
results.size() );
assertEquals( 9L,
results.get( 0 ) );
}
@Test(timeout = 10000)
public void testInfiniteLoopAddingPkgAfterSession() throws Exception {
// JBRULES-3488
String rule = "package org.drools.compiler.test;\n" +
"import " + AccumulateTest.Triple.class.getCanonicalName() + ";\n" +
"rule \"accumulate 2 times\"\n" +
"when\n" +
" $LIST : java.util.List( )" +
" from accumulate( $Triple_1 : Triple( $CN : subject," +
" predicate == \"<http://deductions.sf.net/samples/princing.n3p.n3#number>\", $N : object )," +
" collectList( $N ) )\n" +
" $NUMBER : Number() from accumulate(" +
" $NUMBER_STRING_ : String() from $LIST , sum( Double.parseDouble( $NUMBER_STRING_)) )\n" +
"then\n" +
" System.out.println(\"ok\");\n" +
"end\n";
final KnowledgeBase kbase = getKnowledgeBase();
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
// To reproduce, Need to have 3 object asserted (not less) :
ksession.insert( new Triple( "<http://deductions.sf.net/samples/princing.n3p.n3#CN1>", "<http://deductions.sf.net/samples/princing.n3p.n3#number>", "200" ) );
ksession.insert( new Triple( "<http://deductions.sf.net/samples/princing.n3p.n3#CN2>", "<http://deductions.sf.net/samples/princing.n3p.n3#number>", "100" ) );
ksession.insert( new Triple( "<http://deductions.sf.net/samples/princing.n3p.n3#CN3>", "<http://deductions.sf.net/samples/princing.n3p.n3#number>", "100" ) );
kbase.addKnowledgePackages( loadKnowledgePackagesFromString( rule ) );
ksession.fireAllRules();
}
public static class Triple {
private String subject;
private String predicate;
private String object;
/**
* for javabeans
*/
public Triple() {
}
public Triple( String subject, String predicate, String object ) {
this.subject = subject;
this.predicate = predicate;
this.object = object;
// System.out.print(">>> inst. " + toString() );
}
public String getSubject() {
return subject;
}
public String getPredicate() {
return predicate;
}
public String getObject() {
return object;
}
}
@Test(timeout = 10000)
public void testAccumulateWithVarsOutOfHashOrder() throws Exception {
// JBRULES-3494
String rule = "package com.sample;\n" +
"\n" +
"import java.util.List;\n" +
"\n" +
"declare MessageHolder\n" +
" id : String\n" +
" msg: String\n" +
"end\n" +
"\n" +
"query getResults( String $mId, List $holders )\n" +
" accumulate( \n" +
" $holder : MessageHolder( id == $mId, $ans : msg ),\n" +
" $holders := collectList( $holder )\n" +
" ) \n" +
"end\n" +
"\n" +
"rule \"Init\"\n" +
"when\n" +
"then\n" +
" insert( new MessageHolder( \"1\", \"x\" ) );\n" +
"end\n";
final KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add( ResourceFactory.newReaderResource( new StringReader( rule ) ),
ResourceType.DRL );
if ( kbuilder.hasErrors() ) {
fail( kbuilder.getErrors().toString() );
}
final KnowledgeBase kbase = getKnowledgeBase();
StatefulKnowledgeSession ksession = createKnowledgeSession( kbase );
kbase.addKnowledgePackages( loadKnowledgePackagesFromString( rule ) );
ksession.fireAllRules();
QueryResults res = ksession.getQueryResults( "getResults", "1", Variable.v );
assertEquals( 1, res.size() );
Object o = res.iterator().next().get( "$holders" );
assertTrue( o instanceof List );
assertEquals( 1, ( (List) o ).size() );
}
@Test(timeout = 10000)
public void testAccumulateWithWindow() {
String str = "global java.util.Map map;\n" +
" \n" +
"declare Double\n" +
"@role(event)\n" +
"end\n" +
" \n" +
"declare window Streem\n" +
" Double() over window:length( 10 )\n" +
"end\n" +
" \n" +
"rule \"See\"\n" +
"when\n" +
" $a : Double() from accumulate (\n" +
" $d: Double()\n" +
" from window Streem,\n" +
" sum( $d )\n" +
" )\n" +
"then\n" +
" System.out.println( \"We have a sum \" + $a );\n" +
"end\n";
KieSession ksession = getKieSessionFromContentStrings( str );
Map res = new HashMap();
ksession.setGlobal( "map", res );
ksession.fireAllRules();
for ( int j = 0; j < 33; j++ ) {
ksession.insert( 1.0 * j );
ksession.fireAllRules();
}
}
@Test(timeout = 10000)
public void testAccumulateWithEntryPoint() {
String str = "global java.util.Map map;\n" +
" \n" +
"declare Double\n" +
"@role(event)\n" +
"end\n" +
" \n" +
"rule \"See\"\n" +
"when\n" +
" $a : Double() from accumulate (\n" +
" $d: Double()\n" +
" from entry-point data,\n" +
" sum( $d )\n" +
" )\n" +
"then\n" +
" System.out.println( \"We have a sum \" + $a );\n" +
"end\n";
KieSession ksession = getKieSessionFromContentStrings( str );
Map res = new HashMap();
ksession.setGlobal( "map", res );
ksession.fireAllRules();
for ( int j = 0; j < 33; j++ ) {
ksession.getEntryPoint( "data" ).insert( 1.0 * j );
ksession.fireAllRules();
}
}
@Test(timeout = 10000)
public void testAccumulateWithWindowAndEntryPoint() {
String str = "global java.util.Map map;\n" +
" \n" +
"declare Double\n" +
"@role(event)\n" +
"end\n" +
" \n" +
"declare window Streem\n" +
" Double() over window:length( 10 ) from entry-point data\n" +
"end\n" +
" \n" +
"rule \"See\"\n" +
"when\n" +
" $a : Double() from accumulate (\n" +
" $d: Double()\n" +
" from window Streem,\n" +
" sum( $d )\n" +
" )\n" +
"then\n" +
" System.out.println( \"We have a sum \" + $a );\n" +
"end\n";
KieSession ksession = getKieSessionFromContentStrings( str );
Map res = new HashMap();
ksession.setGlobal( "map", res );
ksession.fireAllRules();
for ( int j = 0; j < 33; j++ ) {
ksession.getEntryPoint( "data" ).insert( 1.0 * j );
ksession.fireAllRules();
}
}
@Test(timeout = 10000)
public void test2AccumulatesWithOr() throws Exception {
// JBRULES-3538
String str =
"import java.util.*;\n" +
"import " + MyPerson.class.getName() + ";\n" +
"global java.util.Map map;\n" +
"dialect \"mvel\"\n" +
"\n" +
"rule \"Test\"\n" +
" when\n" +
" $total : Number()\n" +
" from accumulate( MyPerson( $age: age ),\n" +
" sum( $age ) )\n" +
"\n" +
" $p: MyPerson();\n" +
" $k: List( size > 0 ) from accumulate( MyPerson($kids: kids) from $p.kids,\n" +
" init( ArrayList myList = new ArrayList(); ),\n" +
" action( myList.addAll($kids); ),\n" +
" reverse( myList.removeAll($kids); ),\n" +
" result( myList )\n" +
" )\n" +
"\n" +
" $r : MyPerson(name == \"Jos Jr Jr\")\n" +
" or\n" +
" $r : MyPerson(name == \"Jos\")\n" +
" then\n" +
" Map pMap = map.get( $r.getName() );\n" +
" pMap.put( 'total', $total );\n" +
" pMap.put( 'p', $p );\n" +
" pMap.put( 'k', $k );\n" +
" pMap.put( 'r', $r );\n" +
" map.put('count', ((Integer)map.get('count')) + 1 );\n " +
"end\n";
KieSession ksession = getKieSessionFromContentStrings( str );
List list = new ArrayList();
Map map = new HashMap();
ksession.setGlobal( "map", map );
map.put( "Jos Jr Jr", new HashMap() );
map.put( "Jos", new HashMap() );
map.put( "count", 0 );
MyPerson josJr = new MyPerson( "Jos Jr Jr", 20,
asList( new MyPerson( "John Jr 1st", 10,
asList( new MyPerson( "John Jr Jrx", 4, Collections.<MyPerson>emptyList() ) ) ),
new MyPerson( "John Jr 2nd", 8, Collections.<MyPerson>emptyList() ) ) );
MyPerson jos = new MyPerson( "Jos", 30,
asList( new MyPerson( "Jeff Jr 1st", 10, Collections.<MyPerson>emptyList() ),
new MyPerson( "Jeff Jr 2nd", 8, Collections.<MyPerson>emptyList() ) ) );
ksession.execute( new InsertElementsCommand( asList( new Object[]{josJr, jos} ) ) );
ksession.fireAllRules();
System.out.println( map );
assertEquals( 2, map.get( "count" ) );
Map pMap = (Map) map.get( "Jos Jr Jr" );
assertEquals( 50.0, pMap.get( "total" ) );
List kids = (List) pMap.get( "k" );
assertEquals( 1, kids.size() );
assertEquals( "John Jr Jrx", ( (MyPerson) kids.get( 0 ) ).getName() );
assertEquals( josJr, pMap.get( "p" ) );
assertEquals( josJr, pMap.get( "r" ) );
pMap = (Map) map.get( "Jos" );
assertEquals( 50.0, pMap.get( "total" ) );
kids = (List) pMap.get( "k" );
assertEquals( 1, kids.size() );
assertEquals( "John Jr Jrx", ( (MyPerson) kids.get( 0 ) ).getName() );
assertEquals( josJr, pMap.get( "p" ) );
assertEquals( jos, pMap.get( "r" ) );
}
public static class MyPerson {
public MyPerson( String name, Integer age, Collection<MyPerson> kids ) {
this.name = name;
this.age = age;
this.kids = kids;
}
private String name;
private Integer age;
private Collection<MyPerson> kids;
public String getName() {
return name;
}
public void setName( String name ) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge( Integer age ) {
this.age = age;
}
public Collection<MyPerson> getKids() {
return kids;
}
public void setKids( Collection<MyPerson> kids ) {
this.kids = kids;
}
}
public static class Course {
private int minWorkingDaySize;
public Course( int minWorkingDaySize ) {
this.minWorkingDaySize = minWorkingDaySize;
}
public int getMinWorkingDaySize() {
return minWorkingDaySize;
}
public void setMinWorkingDaySize( int minWorkingDaySize ) {
this.minWorkingDaySize = minWorkingDaySize;
}
}
public static class Lecture {
private Course course;
private int day;
public Lecture( Course course, int day ) {
this.course = course;
this.day = day;
}
public Course getCourse() {
return course;
}
public void setCourse( Course course ) {
this.course = course;
}
public int getDay() {
return day;
}
public void setDay( int day ) {
this.day = day;
}
}
@Test
public void testAccumulateWithExists() {
String str =
"import " + Course.class.getCanonicalName() + "\n" +
"import " + Lecture.class.getCanonicalName() + "\n" +
"global java.util.List list; \n" +
"rule \"minimumWorkingDays\"\n" +
" when\n" +
" $course : Course($minWorkingDaySize : minWorkingDaySize)\n" +
" $dayCount : Number(intValue <= $minWorkingDaySize) from accumulate(\n" +
" $day : Integer()\n" +
" and exists Lecture(course == $course, day == $day),\n" +
" count($day)\n" +
" )\n" +
" // An uninitialized schedule should have no constraints broken\n" +
" exists Lecture(course == $course)\n" +
" then\n" +
" list.add( $course );\n" +
" list.add( $dayCount );\n" +
"end\n";
KieSession ksession = getKieSessionFromContentStrings( str );
List list = new ArrayList();
ksession.setGlobal( "list", list );
Integer day1 = 1;
Integer day2 = 2;
Integer day3 = 3;
Course c = new Course( 2 );
Lecture l1 = new Lecture( c, day1 );
Lecture l2 = new Lecture( c, day2 );
ksession.insert( day1 );
ksession.insert( day2 );
ksession.insert( day3 );
ksession.insert( c );
ksession.insert( l1 );
ksession.insert( l2 );
assertEquals( 1, ksession.fireAllRules() );
assertEquals( 2, list.size() );
assertEquals( c, list.get( 0 ) );
assertEquals( 2l, list.get( 1 ) );
}
@Test
public void testAccumulatesExpireVsCancel() throws Exception {
// JBRULES-3201
String drl = "package com.sample;\n" +
"\n" +
"global java.util.List list; \n" +
"" +
"declare FactTest\n" +
" @role( event ) \n" +
"end\n" +
" \n" +
"rule \"A500 test\"\n" +
"when\n" +
" accumulate (\n" +
" $d : FactTest() over window:time(1m), $tot : count($d); $tot > 0 )\n" +
"then\n" +
" System.out.println( $tot ); \n" +
" list.add( $tot.intValue() ); \n " +
"end\n" +
"\n";
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add( ResourceFactory.newByteArrayResource( drl.getBytes() ), ResourceType.DRL );
assertFalse( kbuilder.hasErrors() );
KieBaseConfiguration kbConf = KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
kbConf.setOption( EventProcessingOption.STREAM );
KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase( kbConf );
kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );
KieSessionConfiguration ksConf = KnowledgeBaseFactory.newKnowledgeSessionConfiguration();
ksConf.setOption( ClockTypeOption.get( "pseudo" ) );
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession( ksConf, null );
ArrayList list = new ArrayList();
ksession.setGlobal( "list", list );
FactType ft = kbase.getFactType( "com.sample", "FactTest" );
ksession.insert( ft.newInstance() );
ksession.fireAllRules();
ksession.insert( ft.newInstance() );
ksession.fireAllRules();
ksession.insert( ft.newInstance() );
ksession.fireAllRules();
SessionPseudoClock clock = ksession.getSessionClock();
clock.advanceTime( 1, TimeUnit.MINUTES );
ksession.fireAllRules();
assertFalse( list.contains( 0 ) );
}
@Test
public void testManySlidingWindows() throws Exception {
String drl = "package com.sample;\n" +
"\n" +
"global java.util.List list; \n" +
"" +
"declare Fakt\n" +
" @role( event ) \n" +
" id : int \n" +
"end\n" +
" \n" +
"rule Init \n" +
"when \n" +
" $i : Integer() \n" +
"then \n" +
" insert( new Fakt( $i ) ); \n" +
"end\n" +
"" +
"rule \"Test\"\n" +
"when\n" +
" accumulate ( $d : Fakt( id > 10 ) over window:length(2), $tot1 : count( $d ) ) \n" +
" accumulate ( $d : Fakt( id < 50 ) over window:length(5), $tot2 : count( $d ) ) \n" +
"then\n" +
" System.out.println( \"Fire!\" ); \n" +
" list.clear();\n " +
" list.add( $tot1.intValue() ); \n" +
" list.add( $tot2.intValue() ); \n" +
"end\n" +
"\n";
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add( ResourceFactory.newByteArrayResource( drl.getBytes() ), ResourceType.DRL );
System.out.println( kbuilder.getErrors() );
assertFalse( kbuilder.hasErrors() );
KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
kbase.addKnowledgePackages( kbuilder.getKnowledgePackages() );
StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession();
List list = new ArrayList();
ksession.setGlobal( "list", list );
ksession.insert( new Integer( 20 ) );
ksession.fireAllRules();
assertEquals( list, asList( 1, 1 ) );
ksession.insert( new Integer( 20 ) );
ksession.fireAllRules();
assertEquals( list, asList( 2, 2 ) );
ksession.insert( new Integer( 20 ) );
ksession.fireAllRules();
assertEquals( list, asList( 2, 3 ) );
ksession.insert( new Integer( 2 ) );
ksession.fireAllRules();
assertEquals( list, asList( 2, 4 ) );
ksession.insert( new Integer( 2 ) );
ksession.fireAllRules();
assertEquals( list, asList( 2, 5 ) );
ksession.insert( new Integer( 2 ) );
ksession.fireAllRules();
assertEquals( list, asList( 2, 5 ) );
}
@Test
public void testImportAccumulateFunction() throws Exception {
String drl = "package org.foo.bar\n"
+ "import accumulate " + TestFunction.class.getCanonicalName() + " f\n"
+ "rule X when\n"
+ " accumulate( $s : String(),\n"
+ " $v : f( $s ) )\n"
+ "then\n"
+ "end\n";
ReleaseId releaseId = new ReleaseIdImpl( "foo", "bar", "1.0" );
KieServices ks = KieServices.Factory.get();
createAndDeployJar( ks, releaseId, drl );
KieContainer kc = ks.newKieContainer( releaseId );
KieSession ksession = kc.newKieSession();
AgendaEventListener ael = mock( AgendaEventListener.class );
ksession.addEventListener( ael );
ksession.insert( "x" );
ksession.fireAllRules();
ArgumentCaptor<AfterMatchFiredEvent> ac = ArgumentCaptor.forClass( AfterMatchFiredEvent.class );
verify( ael ).afterMatchFired( ac.capture() );
assertThat( (Integer) ac.getValue().getMatch().getDeclarationValue( "$v" ), is( Integer.valueOf( 1 ) ) );
}
@Test
public void testImportAccumulateFunctionWithDeclaration() throws Exception {
// DROOLS-750
String drl = "package org.foo.bar\n"
+ "import accumulate " + TestFunction.class.getCanonicalName() + " f;\n"
+ "import " + Person.class.getCanonicalName() + ";\n"
+ "declare Person \n"
+ " @propertyReactive\n"
+ "end\n"
+ "rule X when\n"
+ " accumulate( $s : String(),\n"
+ " $v : f( $s ) )\n"
+ "then\n"
+ "end\n";
ReleaseId releaseId = new ReleaseIdImpl( "foo", "bar", "1.0" );
KieServices ks = KieServices.Factory.get();
createAndDeployJar( ks, releaseId, drl );
KieContainer kc = ks.newKieContainer( releaseId );
KieSession ksession = kc.newKieSession();
AgendaEventListener ael = mock( AgendaEventListener.class );
ksession.addEventListener( ael );
ksession.insert( "x" );
ksession.fireAllRules();
ArgumentCaptor<AfterMatchFiredEvent> ac = ArgumentCaptor.forClass( AfterMatchFiredEvent.class );
verify( ael ).afterMatchFired( ac.capture() );
assertThat( (Integer) ac.getValue().getMatch().getDeclarationValue( "$v" ), is( Integer.valueOf( 1 ) ) );
}
public static class TestFunction implements AccumulateFunction<Serializable> {
@Override
public void writeExternal( ObjectOutput out ) throws IOException {
}
@Override
public void readExternal( ObjectInput in ) throws IOException, ClassNotFoundException {
}
@Override
public Serializable createContext() {
return null;
}
@Override
public void init( Serializable context ) throws Exception {
}
@Override
public void accumulate( Serializable context, Object value ) {
}
@Override
public void reverse( Serializable context, Object value ) throws Exception {
}
@Override
public Object getResult( Serializable context ) throws Exception {
return Integer.valueOf( 1 );
}
@Override
public boolean supportsReverse() {
return true;
}
@Override
public Class<?> getResultType() {
return Number.class;
}
}
@Test
public void testAccumulateWithSharedNode() throws Exception {
// DROOLS-594
String drl =
"rule A when" +
" Double() " +
"then " +
"end " +
"rule B " +
"when " +
" Double() " +
" String() " +
" $list : java.util.List( this not contains \"XX\" ) " +
" $sum : Integer( ) from accumulate ( $i : Integer(), " +
" sum( $i ) ) " +
"then " +
" $list.add( \"XX\" );\n" +
" update( $list );\n" +
" System.out.println(\"FIRED\");\n" +
"end ";
KieHelper helper = new KieHelper();
helper.addContent( drl, ResourceType.DRL );
KieSession ksession = helper.build().newKieSession();
List<String> list = new java.util.ArrayList();
ksession.insert( list );
ksession.insert( 42.0 );
ksession.insert( 9000 );
ksession.insert( "a" );
ksession.insert( "b" );
ksession.fireAllRules();
assertEquals( 1, list.size() );
}
@Test
public void testEmptyAccumulateInSubnetwork() {
// DROOLS-598
String drl =
"global java.util.List list;\n" +
"rule R when\n" +
" $count : Number( ) from accumulate (\n" +
" Integer() and\n" +
" $s: String();\n" +
" count($s)\n" +
" )\n" +
"then\n" +
" list.add($count);\n" +
"end";
KieHelper helper = new KieHelper();
helper.addContent( drl, ResourceType.DRL );
KieSession ksession = helper.build().newKieSession();
List<Long> list = new ArrayList<Long>();
ksession.setGlobal( "list", list );
ksession.insert( 1 );
ksession.fireAllRules();
assertEquals( 1, list.size() );
assertEquals( 0, (long) list.get( 0 ) );
}
@Test
public void testEmptyAccumulateInSubnetworkFollwedByPattern() {
// DROOLS-627
String drl =
"global java.util.List list;\n" +
"rule R when\n" +
" $count : Number( ) from accumulate (\n" +
" Integer() and\n" +
" $s: String();\n" +
" count($s)\n" +
" )\n" +
" Long()\n" +
"then\n" +
" list.add($count);\n" +
"end";
KieHelper helper = new KieHelper();
helper.addContent( drl, ResourceType.DRL );
KieSession ksession = helper.build().newKieSession();
List<Long> list = new ArrayList<Long>();
ksession.setGlobal( "list", list );
ksession.insert( 1 );
ksession.insert( 1L );
ksession.fireAllRules();
assertEquals( 1, list.size() );
assertEquals( 0, (long) list.get( 0 ) );
}
@Test
public void testAccumulateWithoutSeparator() throws Exception {
// DROOLS-602
String str = "package org.drools.compiler\n" +
"\n" +
"rule \"Constraints everywhere\" \n" +
" when\n" +
" $person : Person( $likes : likes )\n" +
" accumulate( Cheese( type == $likes, $price : price )\n" +
" $sum : sum( $price ),\n" +
" $avg : average( $price ),\n" +
" $min : min( $price );\n" +
" $min == 3,\n" +
" $sum > 10 )\n" +
" then\n" +
" // do something\n" +
"end ";
KieServices ks = KieServices.Factory.get();
KieFileSystem kfs = ks.newKieFileSystem().write( "src/main/resources/r1.drl", str );
Results results = ks.newKieBuilder( kfs ).buildAll().getResults();
assertFalse( results.getMessages().isEmpty() );
}
@Test
public void testFromAccumulateWithoutSeparator() throws Exception {
// DROOLS-602
String str = "rule R when\n" +
" $count : Number( ) from accumulate (\n" +
" $s: String()\n" +
" count($s)\n" +
" )\n" +
"then\n" +
" System.out.println($count);\n" +
"end";
KieServices ks = KieServices.Factory.get();
KieFileSystem kfs = ks.newKieFileSystem().write( "src/main/resources/r1.drl", str );
Results results = ks.newKieBuilder( kfs ).buildAll().getResults();
assertFalse( results.getMessages().isEmpty() );
}
@Test
public void testAccFunctionOpaqueJoins() throws Exception {
// DROOLS-661
testAccFunctionOpaqueJoins(PropertySpecificOption.ALLOWED);
}
@Test
public void testAccFunctionOpaqueJoinsWithPropertyReactivity() throws Exception {
// DROOLS-1445
testAccFunctionOpaqueJoins(PropertySpecificOption.ALWAYS);
}
private void testAccFunctionOpaqueJoins(PropertySpecificOption propertySpecificOption) throws Exception {
String str = "package org.test; " +
"import java.util.*; " +
"global List list; " +
"global List list2; " +
"declare Tick " +
" tick : int " +
"end " +
"declare Data " +
" values : List " +
" bias : int = 0 " +
"end " +
"rule Init " +
"when " +
"then " +
" insert( new Data( Arrays.asList( 1, 2, 3 ), 1 ) ); " +
" insert( new Data( Arrays.asList( 4, 5, 6 ), 2 ) ); " +
" insert( new Tick( 0 ) );" +
"end " +
"rule Update " +
" no-loop " +
"when " +
" $i : Integer() " +
" $t : Tick() " +
"then " +
" System.out.println( 'Set tick to ' + $i ); " +
" modify( $t ) { " +
" setTick( $i ); " +
" } " +
"end " +
"rule M " +
" dialect 'mvel' " +
"when " +
" Tick( $index : tick ) " +
" accumulate ( $data : Data( $bias : bias )," +
" $tot : sum( $data.values[ $index ] + $bias ) ) " +
"then " +
" System.out.println( $tot + ' for J ' + $index ); " +
" list.add( $tot ); " +
"end " +
"rule J " +
"when " +
" Tick( $index : tick ) " +
" accumulate ( $data : Data( $bias : bias )," +
" $tot : sum( ((Integer)$data.getValues().get( $index )) + $bias ) ) " +
"then " +
" System.out.println( $tot + ' for M ' + $index ); " +
" list2.add( $tot ); " +
"end ";
KieHelper helper = new KieHelper( propertySpecificOption );
KieSession ks = helper.addContent( str, ResourceType.DRL ).build().newKieSession();
List list = new ArrayList();
ks.setGlobal( "list", list );
List list2 = new ArrayList();
ks.setGlobal( "list2", list2 );
// init data
ks.fireAllRules();
assertEquals( asList( 8.0 ), list );
assertEquals( asList( 8.0 ), list2 );
ks.insert( 1 );
ks.fireAllRules();
assertEquals( asList( 8.0, 10.0 ), list );
assertEquals( asList( 8.0, 10.0 ), list2 );
ks.insert( 2 );
ks.fireAllRules();
assertEquals( asList( 8.0, 10.0, 12.0 ), list );
assertEquals( asList( 8.0, 10.0, 12.0 ), list2 );
}
public static class ExpectedMessage {
String type;
public ExpectedMessage( String type ) {
this.type = type;
}
public String getType() {
return type;
}
}
public static class ExpectedMessageToRegister {
String type;
boolean registered = false;
List<ExpectedMessage> msgs = new ArrayList<ExpectedMessage>();
public ExpectedMessageToRegister( String type ) {
this.type = type;
}
public String getType() {
return type;
}
public List<ExpectedMessage> getExpectedMessages() {
return msgs;
}
public boolean isRegistered() {
return registered;
}
public void setRegistered( boolean registered ) {
this.registered = registered;
}
}
@Test
public void testReaccumulateForLeftTuple() {
String drl1 =
"import " + ExpectedMessage.class.getCanonicalName() + ";\n"
+ "import " + List.class.getCanonicalName() + ";\n"
+ "import " + ExpectedMessageToRegister.class.getCanonicalName() + ";\n"
+ "\n\n"
+ "rule \"Modify\"\n"
+ " when\n"
+ " $etr: ExpectedMessageToRegister(registered == false)"
+ " then\n"
+ " modify( $etr ) { setRegistered( true ) }"
+ " end\n"
+ "rule \"Collect\"\n"
+ " salience 200 \n"
+ " when\n"
+ " etr: ExpectedMessageToRegister($type: type)"
+ " $l : List( ) from collect( ExpectedMessage( type == $type ) from etr.expectedMessages )"
+ " then\n"
+ " java.lang.System.out.println( $l.size() );"
+ " end\n";
KieSession ksession = new KieHelper().addContent( drl1, ResourceType.DRL )
.build()
.newKieSession();
ExpectedMessage psExpMsg1 = new ExpectedMessage( "Index" );
ExpectedMessageToRegister etr1 = new ExpectedMessageToRegister( "Index" );
etr1.msgs.add( psExpMsg1 );
ksession.insert( etr1 );
ksession.fireAllRules();
}
@Test
public void testNoLoopAccumulate() {
// DROOLS-694
String drl1 =
"import " + AtomicInteger.class.getCanonicalName() + ";\n" +
"rule NoLoopAccumulate\n" +
"no-loop\n" +
"when\n" +
" accumulate( $s : String() ; $val : count($s) )\n" +
" $a : AtomicInteger( )\n" +
"then\n" +
" modify($a) { set($val.intValue()) }\n" +
"end";
KieSession ksession = new KieHelper().addContent( drl1, ResourceType.DRL )
.build()
.newKieSession();
AtomicInteger counter = new AtomicInteger( 0 );
ksession.insert( counter );
ksession.insert( "1" );
ksession.fireAllRules();
assertEquals( 1, counter.get() );
ksession.insert( "2" );
ksession.fireAllRules();
assertEquals( 2, counter.get() );
}
private KieSession getKieSessionFromResources( String... classPathResources ) {
KieBase kbase = loadKnowledgeBase( null, null, classPathResources );
return kbase.newKieSession();
}
private KieBase loadKieBaseFromString( String... drlContentStrings ) {
return loadKnowledgeBaseFromString( null, null, drlContentStrings );
}
private KieSession getKieSessionFromContentStrings( String... drlContentStrings ) {
KieBase kbase = loadKnowledgeBaseFromString( null, null, drlContentStrings );
return kbase.newKieSession();
}
@Test
public void testAccumulateWithOr() {
// DROOLS-839
String drl1 =
"import " + Converter.class.getCanonicalName() + ";\n" +
"global java.util.List list;\n" +
"rule R when\n" +
" (or\n" +
" Integer (this == 1)\n" +
" Integer (this == 2)\n" +
" )\n" +
"String( $length : length )\n" +
"accumulate ( $c : Converter(), $result : sum( $c.convert($length) ) )\n" +
"then\n" +
" list.add($result);\n" +
"end";
KieSession ksession = new KieHelper().addContent( drl1, ResourceType.DRL )
.build()
.newKieSession();
List<Integer> list = new ArrayList<Integer>();
ksession.setGlobal( "list", list );
ksession.insert( 1 );
ksession.insert( "hello" );
ksession.insert( new Converter() );
ksession.fireAllRules();
assertEquals( 1, list.size() );
assertEquals( "hello".length(), (int)list.get(0), 0.01 );
}
@Test
public void testMvelAccumulateWithOr() {
// DROOLS-839
String drl1 =
"import " + Converter.class.getCanonicalName() + ";\n" +
"global java.util.List list;\n" +
"rule R dialect \"mvel\" when\n" +
" (or\n" +
" Integer (this == 1)\n" +
" Integer (this == 2)\n" +
" )\n" +
"String( $length : length )\n" +
"accumulate ( $c : Converter(), $result : sum( $c.convert($length) ) )\n" +
"then\n" +
" list.add($result);\n" +
"end";
KieSession ksession = new KieHelper().addContent( drl1, ResourceType.DRL )
.build()
.newKieSession();
List<Double> list = new ArrayList<Double>();
ksession.setGlobal( "list", list );
ksession.insert( 1 );
ksession.insert( "hello" );
ksession.insert( new Converter() );
ksession.fireAllRules();
assertEquals( 1, list.size() );
assertEquals( "hello".length(), list.get(0), 0.01 );
}
public static class Converter {
public static int convert(int i) {
return i;
}
}
@Test
public void testNormalizeStagedTuplesInAccumulate() {
// DROOLS-998
String drl =
"global java.util.List list;\n" +
"rule R when\n" +
" not( String() )\n" +
" accumulate(\n" +
" $l: Long();\n" +
" count($l)\n" +
" )\n" +
" ( Boolean() or not( Float() ) )\n" +
"then\n" +
" list.add( \"fired\" ); \n" +
" insert(new String());\n" +
"end\n";
KieSession ksession = new KieHelper().addContent( drl, ResourceType.DRL )
.build()
.newKieSession();
List<String> list = new ArrayList<String>();
ksession.setGlobal( "list", list );
ksession.fireAllRules();
assertEquals( 1, list.size() );
}
@Test
public void testIncompatibleTypeOnAccumulateFunction() {
// DROOLS-1243
String drl =
"import " + MyPerson.class.getCanonicalName() + ";\n" +
"import " + BigDecimal.class.getCanonicalName() + ";\n" +
"global java.util.List list;\n" +
"rule R when\n" +
" $theFrom : BigDecimal() from accumulate(MyPerson( $val : age ); \n" +
" sum( $val ) )\n" +
"then\n" +
" list.add($theFrom);\n" +
"end\n";
KieServices ks = KieServices.Factory.get();
KieFileSystem kfs = ks.newKieFileSystem().write( "src/main/resources/r1.drl", drl );
Results results = ks.newKieBuilder( kfs ).buildAll().getResults();
assertFalse( results.getMessages().isEmpty() );
}
@Test
public void testIncompatibleListOnAccumulateFunction() {
// DROOLS-1243
String drl =
"import " + MyPerson.class.getCanonicalName() + ";\n" +
"import " + BigDecimal.class.getCanonicalName() + ";\n" +
"global java.util.List list;\n" +
"rule R when\n" +
" $theFrom : String() from accumulate(MyPerson( $val : age ); \n" +
" collectList( $val ) )\n" +
"then\n" +
" list.add($theFrom);\n" +
"end\n";
KieServices ks = KieServices.Factory.get();
KieFileSystem kfs = ks.newKieFileSystem().write( "src/main/resources/r1.drl", drl );
Results results = ks.newKieBuilder( kfs ).buildAll().getResults();
assertFalse( results.getMessages().isEmpty() );
}
@Test
public void testTypedSumOnAccumulate() {
// DROOLS-1175
String drl1 =
"global java.util.List list;\n" +
"rule R when\n" +
" $i : Integer()\n" +
" accumulate ( $s : String(), $result : sum( $s.length() ) )\n" +
"then\n" +
" list.add($result);\n" +
"end";
KieSession ksession = new KieHelper().addContent( drl1, ResourceType.DRL )
.build()
.newKieSession();
List<Integer> list = new ArrayList<Integer>();
ksession.setGlobal( "list", list );
ksession.insert( 1 );
ksession.insert( "hello" );
ksession.insert( "hi" );
ksession.fireAllRules();
assertEquals( 1, list.size() );
assertEquals( "hello".length() + "hi".length(), (int)list.get(0) );
}
@Test
public void testSumAccumulateOnNullValue() {
// DROOLS-1242
String drl1 =
"import " + PersonWithBoxedAge.class.getCanonicalName() + ";\n" +
"global java.util.List list;\n" +
"rule R when\n" +
" accumulate ( $p : PersonWithBoxedAge(), $result : sum( $p.getAge() ) )\n" +
"then\n" +
" list.add($result);\n" +
"end";
KieSession ksession = new KieHelper().addContent( drl1, ResourceType.DRL )
.build()
.newKieSession();
List<Integer> list = new ArrayList<Integer>();
ksession.setGlobal( "list", list );
ksession.insert( new PersonWithBoxedAge("me", 30) );
ksession.insert( new PersonWithBoxedAge("you", 40) );
ksession.insert( new PersonWithBoxedAge("she", null) );
ksession.fireAllRules();
assertEquals( 1, list.size() );
assertEquals( 70, (int)list.get(0) );
}
@Test
public void testMinAccumulateOnComparable() {
String drl1 =
"import " + PersonWithBoxedAge.class.getCanonicalName() + ";\n" +
"global java.util.List list;\n" +
"rule R when\n" +
" accumulate ( $p : PersonWithBoxedAge(), $result : min( $p ) )\n" +
"then\n" +
" list.add($result);\n" +
"end";
KieSession ksession = new KieHelper().addContent( drl1, ResourceType.DRL )
.build()
.newKieSession();
List<PersonWithBoxedAge> list = new ArrayList<PersonWithBoxedAge>();
ksession.setGlobal( "list", list );
ksession.insert( new PersonWithBoxedAge("me", 30) );
ksession.insert( new PersonWithBoxedAge("you", 40) );
ksession.insert( new PersonWithBoxedAge("she", 25) );
ksession.fireAllRules();
assertEquals( 1, list.size() );
assertEquals( "she", list.get(0).getName() );
}
@Test
public void testMaxAccumulateOnComparable() {
String drl1 =
"import " + PersonWithBoxedAge.class.getCanonicalName() + ";\n" +
"global java.util.List list;\n" +
"rule R when\n" +
" accumulate ( $p : PersonWithBoxedAge(), $result : max( $p ) )\n" +
"then\n" +
" list.add($result);\n" +
"end";
KieSession ksession = new KieHelper().addContent( drl1, ResourceType.DRL )
.build()
.newKieSession();
List<PersonWithBoxedAge> list = new ArrayList<PersonWithBoxedAge>();
ksession.setGlobal( "list", list );
ksession.insert( new PersonWithBoxedAge("me", 30) );
ksession.insert( new PersonWithBoxedAge("you", 40) );
ksession.insert( new PersonWithBoxedAge("she", 25) );
ksession.fireAllRules();
assertEquals( 1, list.size() );
assertEquals( "you", list.get(0).getName() );
}
public static class PersonWithBoxedAge implements Comparable<PersonWithBoxedAge> {
private final String name;
private final Integer age;
public PersonWithBoxedAge( String name, Integer age ) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
@Override
public int compareTo( PersonWithBoxedAge other ) {
return age.compareTo( other.getAge() );
}
}
@Test
public void testTypedMaxOnAccumulate() {
// DROOLS-1175
String drl1 =
"global java.util.List list;\n" +
"rule R when\n" +
" $i : Integer()\n" +
" $result : Integer() from accumulate ( $s : String(), max( $s.length() ) )\n" +
"then\n" +
" list.add($result);\n" +
"end";
KieSession ksession = new KieHelper().addContent( drl1, ResourceType.DRL )
.build()
.newKieSession();
List<Integer> list = new ArrayList<Integer>();
ksession.setGlobal( "list", list );
ksession.insert( 1 );
ksession.insert( "hello" );
ksession.insert( "hi" );
ksession.fireAllRules();
assertEquals( 1, list.size() );
assertEquals( "hello".length(), (int)list.get(0) );
}
@Test
public void testVarianceDouble() {
String drl =
"import org.drools.compiler.Cheese\n" +
"global java.util.List list;\n" +
"rule R when\n" +
" accumulate(\n" +
" Cheese($price : price);\n" +
" $result : variance($price)\n" +
" )\n" +
"then\n" +
" list.add($result);\n" +
"end";
KieBase kieBase = new KieHelper().addContent(drl, ResourceType.DRL).build();
assertEquals(0.00, cheeseInsertsFunction(kieBase, 3, 3, 3, 3, 3), 0.01);
assertEquals(0.80, cheeseInsertsFunction(kieBase, 4, 4, 3, 2, 2), 0.01);
assertEquals(1.20, cheeseInsertsFunction(kieBase, 5, 3, 3, 2, 2), 0.01);
assertEquals(2.80, cheeseInsertsFunction(kieBase, 5, 5, 2, 2, 1), 0.01);
assertEquals(2.80, cheeseInsertsFunction(kieBase, 6, 3, 3, 2, 1), 0.01);
assertEquals(4.40, cheeseInsertsFunction(kieBase, 6, 5, 2, 1, 1), 0.01);
assertEquals(16.00, cheeseInsertsFunction(kieBase, 11, 1, 1, 1, 1), 0.01);
assertEquals(36.00, cheeseInsertsFunction(kieBase, 15, 0, 0, 0, 0), 0.01);
}
@Test
public void testStandardDeviationDouble() {
String drl =
"import org.drools.compiler.Cheese\n" +
"global java.util.List list;\n" +
"rule R when\n" +
" accumulate(\n" +
" Cheese($price : price);\n" +
" $result : standardDeviation($price)\n" +
" )\n" +
"then\n" +
" list.add($result);\n" +
"end";
KieBase kieBase = new KieHelper().addContent(drl, ResourceType.DRL).build();
assertEquals(0.00, cheeseInsertsFunction(kieBase, 3, 3, 3, 3, 3), 0.01);
assertEquals(0.89, cheeseInsertsFunction(kieBase, 4, 4, 3, 2, 2), 0.01);
assertEquals(1.10, cheeseInsertsFunction(kieBase, 5, 3, 3, 2, 2), 0.01);
assertEquals(1.67, cheeseInsertsFunction(kieBase, 5, 5, 2, 2, 1), 0.01);
assertEquals(1.67, cheeseInsertsFunction(kieBase, 6, 3, 3, 2, 1), 0.01);
assertEquals(2.10, cheeseInsertsFunction(kieBase, 6, 5, 2, 1, 1), 0.01);
assertEquals(4.00, cheeseInsertsFunction(kieBase, 11, 1, 1, 1, 1), 0.01);
assertEquals(6.00, cheeseInsertsFunction(kieBase, 15, 0, 0, 0, 0), 0.01);
}
private double cheeseInsertsFunction(KieBase kieBase, int... prices) {
KieSession ksession = kieBase.newKieSession();
List<Double> list = new ArrayList<>();
ksession.setGlobal("list", list);
for (int price : prices) {
ksession.insert(new Cheese("stilton", price));
}
ksession.fireAllRules();
assertEquals(1, list.size());
double result = list.get(0);
FactHandle triggerReverseHandle = ksession.insert(new Cheese("triggerReverse", 7));
ksession.fireAllRules();
ksession.delete(triggerReverseHandle);
list.clear();
ksession.fireAllRules();
assertEquals(1, list.size());
// Check that the reserse() does the opposite of the accumulate()
assertEquals(result, list.get(0), 0.001);
ksession.dispose();
return list.get(0);
}
@Test
public void testConcurrentLeftAndRightUpdate() {
// DROOLS-1517
String drl = "package P;\n"
+ "import " + Visit.class.getCanonicalName() + ";\n"
+ "global java.util.List list\n"
+ "rule OvercommittedMechanic\n"
+ "when\n"
+ " Visit($bucket : bucket)\n"
+ " $weeklyCommitment : Number() from accumulate(\n"
+ " Visit($duration : duration, bucket == $bucket),\n"
+ " sum($duration)\n"
+ " )\n"
+ "then\n"
+ " list.add($weeklyCommitment);"
+ "end";
KieSession kieSession = new KieHelper().addContent(drl, ResourceType.DRL).build().newKieSession();
List list = new ArrayList();
kieSession.setGlobal( "list", list );
Visit visit1 = new Visit(1.0);
Visit visit2 = new Visit(2.0);
Visit visit3 = new Visit(3.0);
Visit visit4 = new Visit(4.0);
int bucketA = 1;
int bucketB = 2;
visit1.setBucket(bucketA);
visit2.setBucket(bucketB);
visit3.setBucket(bucketB);
visit4.setBucket(bucketB);
FactHandle fhVisit1 = kieSession.insert(visit1);
FactHandle fhVisit2 = kieSession.insert(visit2);
FactHandle fhVisit3 = kieSession.insert(visit3);
FactHandle fhVisit4 = kieSession.insert(visit4);
kieSession.fireAllRules();
assertTrue( containsExactlyAndClear( list, 9.0, 9.0, 9.0, 1.0 ) );
kieSession.update(fhVisit4, visit4);
kieSession.update(fhVisit3, visit3.setBucket(bucketA));
kieSession.update(fhVisit1, visit1.setBucket(bucketB));
kieSession.fireAllRules();
assertTrue( containsExactlyAndClear( list, 7.0, 7.0, 3.0, 7.0 ) );
kieSession.update(fhVisit1, visit1.setBucket(bucketA));
kieSession.fireAllRules();
assertTrue( list.containsAll( asList( 6.0, 4.0, 6.0, 4.0 ) ) );
}
public static class Visit {
private static int TAG = 1;
private final double duration;
private int bucket;
private final int tag;
public Visit(double duration) {
this.duration = duration;
this.tag = TAG++;
}
public int getBucket() {
return bucket;
}
public Visit setBucket(int bucket) {
this.bucket = bucket;
return this;
}
public double getDuration() {
return duration;
}
@Override
public String toString() {
return "Visit[" + tag + "]";
}
}
private <T> boolean containsExactlyAndClear(List<T> list, T... values) {
if (list.size() != values.length) {
return false;
}
for (T value : values) {
if (!list.remove( value )) {
System.err.println(value + " not present");
return false;
}
}
return list.isEmpty();
}
@Test
public void testDoubleAccumulate() {
// DROOLS-1530
String drl = "package P;"
+ "import " + BusStop.class.getCanonicalName() + ";\n"
+ "import " + Coach.class.getCanonicalName() + ";\n"
+ "import " + Shuttle.class.getCanonicalName() + ";\n"
+ "\n"
+ "global java.util.List result;\n"
+ "\n"
+ "rule coachCapacity\n"
+ " when\n"
+ " $coach : Coach()\n"
+ " accumulate(\n"
+ " BusStop(bus == $coach);\n"
+ " count()\n"
+ " )\n"
+ "\n"
+ " $shuttle : Shuttle()\n"
+ " accumulate(\n"
+ " BusStop(bus == $coach)\n"
+ " and BusStop(bus == $shuttle);\n"
+ " $result : count()\n"
+ " )\n"
+ " then\n"
+ " result.add($result);\n"
+ "end";
KieBase kieBase = new KieHelper().addContent(drl, ResourceType.DRL).build();
KieSession kieSession = kieBase.newKieSession();
ArrayList<Integer> result = new ArrayList<Integer>();
kieSession.setGlobal("result", result);
int id = 1;
Coach coach1 = new Coach( id++ );
Coach coach2 = new Coach( id++ );
Shuttle shuttle = new Shuttle( id++ );
BusStop stop1 = new BusStop( id++ );
BusStop stop2 = new BusStop( id++ );
stop2.setBus(coach2);
FactHandle fhCoach1 = kieSession.insert(coach1);
FactHandle fhCoach2 = kieSession.insert(coach2);
FactHandle fhShuttle = kieSession.insert(shuttle);
FactHandle fhStop1 = kieSession.insert(stop1);
FactHandle fhStop2 = kieSession.insert(stop2);
kieSession.fireAllRules();
result.clear();
kieSession.update(fhShuttle, shuttle);
kieSession.update(fhStop2, stop2);
kieSession.fireAllRules();
result.clear();
kieSession.update(fhShuttle, shuttle);
stop1.setBus(shuttle);
kieSession.update(fhStop1, stop1);
kieSession.fireAllRules();
ArrayList<Integer> actual = new ArrayList<Integer>(result);
Collections.sort(actual);
result.clear();
kieSession.dispose();
kieSession = kieBase.newKieSession();
kieSession.setGlobal("result", result);
// Insert everything into a fresh session to see the uncorrupted score
kieSession.insert(coach1);
kieSession.insert(coach2);
kieSession.insert(shuttle);
kieSession.insert(stop1);
kieSession.insert(stop2);
kieSession.fireAllRules();
ArrayList<Integer> expected = new ArrayList<Integer>(result);
Collections.sort(expected);
System.out.println("expected = " + expected);
System.out.println("actual = " + actual);
assertEquals(expected, actual);
}
public interface Bus { }
public static class Coach implements Bus {
private final int id;
public Coach( int id ) {
this.id = id;
}
public int getId() {
return id;
}
@Override
public String toString() {
return "Coach[" + id + "]";
}
}
public static class Shuttle implements Bus {
private final int id;
public Shuttle( int id ) {
this.id = id;
}
public int getId() {
return id;
}
@Override
public String toString() {
return "Shuttle[" + id + "]";
}
}
public static class BusStop {
private final int id;
private Bus bus;
public BusStop( int id ) {
this.id = id;
}
public Bus getBus() {
return bus;
}
public void setBus(Bus bus) {
this.bus = bus;
}
public int getId() {
return id;
}
@Override
public String toString() {
return "BusStop[" + id + "]";
}
}
}