/*
* JBoss, Home of Professional Open Source
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.internal.soa.esb.services.rules;
import static org.jboss.soa.esb.services.rules.RuleServicePropertiesNames.StringValue.FIRE_UNTIL_HALT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import junit.framework.JUnit4TestAdapter;
import org.jboss.internal.soa.esb.services.routing.cbr.Order;
import org.jboss.internal.soa.esb.util.StreamUtils;
import org.jboss.soa.esb.ConfigurationException;
import org.jboss.soa.esb.actions.Counter;
import org.jboss.soa.esb.common.Environment;
import org.jboss.soa.esb.message.Message;
import org.jboss.soa.esb.message.format.MessageFactory;
import org.jboss.soa.esb.message.format.MessageType;
import org.jboss.soa.esb.message.mapping.ObjectMapper;
import org.jboss.soa.esb.message.mapping.ObjectMappingException;
import org.jboss.soa.esb.services.rules.RuleInfo;
import org.jboss.soa.esb.services.rules.StatefulRuleInfo;
import org.jboss.soa.esb.util.ClassUtil;
import org.junit.Before;
import org.junit.Test;
/**
* Unit test for {@link DroolsRuleService}
* <p/>
*
* @author <a href="mailto:dbevenius@redhat.com">Daniel Bevenius</a>
*
*/
public class DroolsRuleServiceUnitTest
{
private DroolsRuleService ruleService = new DroolsRuleService();
private DroolsRuleBaseState ruleBaseState;
private Message message;
private Order order;
private ArrayList<String> messagePathList;
@Test
public void executeStatelessRules()
{
Map<String,Object> globals = getGlobalsWithDestAndMessage();
RuleInfo ruleInfo = new RuleInfoBuilder().globals(globals).build();
message = ruleBaseState.executeStatelessRules( ruleInfo, message );
ArrayList<String> destinations = getDestinations( globals );
assertTrue( destinations.size() == 1 );
}
@Test
public void executeStatelessRulesWithRuleInfo() throws RuleServiceException
{
RuleInfoBuilder builder = new RuleInfoBuilder("JBossESBRules.drl");
Map<String,Object> globals = getGlobalsWithDestAndMessage();
builder.globals(globals);
message = ruleService.executeStatelessRules(builder.build(), message);
ArrayList<String> destinations = getDestinations( globals );
assertTrue( destinations.size() == 1 );
}
@Test
public void executeStatelessRulesWithAuditLogging() throws IOException, RuleServiceException
{
File file = null;
try
{
RuleInfoBuilder builder = new RuleInfoBuilder("JBossESBRules.drl");
Map<String,Object> globals = getGlobalsWithDestAndMessage();
builder.globals(globals);
file = File.createTempFile(getClass().getSimpleName() + "-", ".log");
String filePath = file.getAbsolutePath();
file.delete();
assertFalse(file.exists());
builder.auditFile(filePath.substring(0, filePath.length()-4));
message = ruleService.executeStatelessRules(builder.build(), message);
ArrayList<String> destinations = getDestinations( globals );
assertTrue( destinations.size() == 1 );
file = new File(filePath);
assertTrue(file.exists());
}
finally
{
if (file != null && file.exists())
{
file.delete();
}
}
}
@Test
public void executeStatefulRulesWithAuditLogging() throws IOException, RuleServiceException
{
File file = null;
try
{
RuleInfoBuilder builder = new RuleInfoBuilder("JBossESBRules.drl");
Map<String,Object> globals = getGlobalsWithDestAndMessage();
builder.globals(globals);
file = File.createTempFile(getClass().getSimpleName() + "-", ".log");
String filePath = file.getAbsolutePath();
file.delete();
assertFalse(file.exists());
builder.auditFile(filePath.substring(0, filePath.length()-4));
StatefulRuleInfo ruleInfo = new StatefulRuleInfoImpl(builder.build(), true, false);
message = ruleService.executeStatefulRules(ruleInfo, message);
ArrayList<String> destinations = getDestinations( globals );
assertTrue( destinations.size() == 1 );
file = new File(filePath);
assertTrue(file.exists());
}
finally
{
if (file != null && file.exists())
{
file.delete();
}
}
}
@Test
public void executeStatefulRulesWithFireUntilHalt() throws InterruptedException, RuleServiceException
{
Map<String,Object> globals = getGlobalsWithDestAndMessage();
final RuleInfo ruleInfo = new RuleInfoBuilder("JBossESBRules.drl")
.globals(globals).ruleFireMethod(FIRE_UNTIL_HALT.name()).build();
StatefulRuleInfoImpl waitRuleInfo = new StatefulRuleInfoImpl(ruleInfo, false, false);
// this kicks off a new thread because of FIRE_UNTIL_HALT
ruleService.executeStatefulRules(waitRuleInfo, message);
boolean success;
int i=0;
do {
success = (getDestinations(globals).size() == 1);
// we will wait a maximum of 60 iterations (~ 1 minute) before we give up
if (i++ == 60) {
break;
}
Thread.sleep(1000);
} while (!success);
StatefulRuleInfo haltRuleInfo = new StatefulRuleInfoImpl(ruleInfo, true, true);
// this halts the kicked-off thread
ruleService.executeStatefulRules(haltRuleInfo, message);
assertTrue(success);
}
@Test
public void executeStatelessRulesFromDecisionTableReload() throws RuleServiceException
{
Map<String,Object> globals = getGlobalsWithDest();
final String decisionTable = "RuleBaseHelper.xls";
RuleInfo ruleInfo = new RuleInfoBuilder(decisionTable).reload(true).globals(globals).build();
message = ruleService.executeStatelessRulesFromDecisionTable( ruleInfo, message );
ArrayList<String> destinations = getDestinations( globals );
assertTrue( destinations.size() == 1 );
}
@Test
public void executeStatelessRulesFromDecisionTableReloadWithRuleInfo() throws RuleServiceException
{
RuleInfoBuilder builder = new RuleInfoBuilder("RuleBaseHelper.xls");
Map<String,Object> globals = getGlobalsWithDest();
builder.globals(globals);
builder.reload(true);
message = ruleService.executeStatelessRulesFromDecisionTable(builder.build(), message);
ArrayList<String> destinations = getDestinations( globals );
assertTrue( destinations.size() == 1 );
}
@Test
public void executeStatelessRulesFromDecisionTable() throws RuleServiceException
{
Map<String,Object> globals = getGlobalsWithDest();
final String decisionTable = "RuleBaseHelper.xls";
RuleInfo ruleInfo = new RuleInfoBuilder(decisionTable).reload(false).globals(globals).build();
StatefulRuleInfo statefulRuleInfo = new StatefulRuleInfoImpl(ruleInfo, false, false);
message = ruleService.executeStatelessRulesFromDecisionTable( statefulRuleInfo, message );
ArrayList<String> destinations = getDestinations( globals );
assertTrue( destinations.size() == 1 );
}
@Test
public void executeStatelessRulesFromDecisionTableWithRuleInfo() throws RuleServiceException
{
RuleInfoBuilder builder = new RuleInfoBuilder("RuleBaseHelper.xls");
Map<String,Object> globals = getGlobalsWithDest();
builder.globals(globals);
builder.reload(false);
message = ruleService.executeStatelessRulesFromDecisionTable(builder.build(), message);
ArrayList<String> destinations = getDestinations( globals );
assertTrue( destinations.size() == 1 );
}
@Test
public void executeStatefulRulesFromDecisionTableReload() throws RuleServiceException
{
Map<String,Object> globals = getGlobalsWithDest();
final String decisionTable = "RuleBaseHelper.xls";
final RuleInfo ruleInfo = new RuleInfoBuilder(decisionTable).reload(true).globals(globals).build();
final StatefulRuleInfoImpl statefulRuleInfo = new StatefulRuleInfoImpl(ruleInfo, false, false);
message = ruleService.executeStatefulRulesFromDecisionTable( statefulRuleInfo, message );
ArrayList<String> destinations = getDestinations( globals );
assertTrue( destinations.size() == 1 );
}
@Test
public void executeStatefulRulesFromDecisionTable() throws RuleServiceException
{
Map<String,Object> globals = getGlobalsWithDest();
final String decisionTable = "RuleBaseHelper.xls";
final RuleInfo ruleInfo = new RuleInfoBuilder(decisionTable).reload(false).globals(globals).build();
final StatefulRuleInfoImpl statefulRuleInfo = new StatefulRuleInfoImpl(ruleInfo, false, false);
message = ruleService.executeStatefulRulesFromDecisionTable( statefulRuleInfo, message );
ArrayList<String> destinations = getDestinations( globals );
assertTrue( destinations.size() == 1 );
}
@Test
public void executeStatefulRules() throws RuleServiceException
{
Map<String,Object> globals = getGlobalsWithDestAndMessage();
final RuleInfo ruleInfo = new RuleInfoBuilder("JBossESBRules.drl").reload(true).globals(globals).build();
final StatefulRuleInfoImpl statefulRuleInfo = new StatefulRuleInfoImpl(ruleInfo, false, false);
message = ruleService.executeStatefulRules( statefulRuleInfo, message );
ArrayList<String> destinations = getDestinations( globals );
assertTrue( destinations.size() == 1 );
}
@Test
public void executeStatefulRulesDrl() throws RuleServiceException
{
Map<String,Object> globals = getGlobalsWithDestAndMessage();
RuleInfo ruleInfo = new RuleInfoBuilder("JBossESBRules.drl").reload(true).globals(globals).build();
StatefulRuleInfoImpl statefulRuleInfo = new StatefulRuleInfoImpl(ruleInfo, false, false);
message = ruleService.executeStatefulRules( statefulRuleInfo, message );
ArrayList<String> destinations = getDestinations( globals );
assertTrue( destinations.size() == 1 );
}
@Test
public void executeStatelessRulesDrlWithDsl() throws RuleServiceException, ConfigurationException, UnsupportedEncodingException
{
Message msg = MessageFactory.getInstance().getMessage();
InputStream resourceAsStream = ClassUtil.getResourceAsStream( "/" + "5KB_message.xml", getClass() );
String contents = StreamUtils.readStreamString( resourceAsStream, "UTF-8" );
msg.getBody().add( contents );
Map<String,Object> globals = getGlobalsWithDest();
boolean ruleReload = true;
// first run
long startTime = System.nanoTime();
RuleInfo ruleInfo = new RuleInfoBuilder("RulesWithDsl.drl").dslSource("XPathLanguage.dsl").reload(ruleReload).globals(globals).build();
message = ruleService.executeStatelessRules( ruleInfo, msg );
ArrayList<String> destinations = getDestinations( globals );
assertTrue( destinations.size() == 1 );
long procTime = System.nanoTime() - startTime;
long firstRun = TimeUnit.NANOSECONDS.toMillis( procTime ) ;
System.out.println( "Timed First run : " + firstRun + "ms" );
// second run
startTime = System.nanoTime();
message = ruleService.executeStatelessRules( ruleInfo, msg );
procTime = System.nanoTime() - startTime;
long secondRun = TimeUnit.NANOSECONDS.toMillis( procTime ) ;
System.out.println( "Timed Second run : " + secondRun + "ms" );
destinations = getDestinations( globals );
assertTrue( destinations.size() == 2 );
}
@Test
public void executeStatelessRulesDrlWithDslAndNamespaces() throws RuleServiceException, ConfigurationException, UnsupportedEncodingException
{
Message msg = MessageFactory.getInstance().getMessage();
InputStream resourceAsStream = ClassUtil.getResourceAsStream( "/" + "5KBNS_message.xml", getClass() );
String contents = StreamUtils.readStreamString( resourceAsStream, "UTF-8" );
msg.getBody().add( contents );
Map<String,Object> globals = getGlobalsWithDest();
boolean ruleReload = true;
RuleInfo ruleInfo = new RuleInfoBuilder("RulesWithDslNS.drl").dslSource("XPathLanguage.dsl").reload(ruleReload).globals(globals).build();
message = ruleService.executeStatelessRules( ruleInfo, msg );
ArrayList<String> destinations = getDestinations( globals );
assertEquals( 3 , destinations.size() );
}
@Test
public void executeStatefulRulesContinueSession() throws RuleServiceException, ObjectMappingException
{
Message message = createMessageWithOrder( order );
Map<String,Object> globals = getGlobalsWithMessage( message );
ArrayList<String> messagePathList = new ArrayList<String>();
messagePathList.add("body.Order");
messagePathList.add("body.Counter");
// process message
List<Object> objectList = new ObjectMapper().createObjectList(message, messagePathList);
RuleInfo ruleInfo = new RuleInfoBuilder("JBossESBPricingRulesStateful.drl").reload(true).globals(globals).defaultFacts(objectList).build();
StatefulRuleInfoImpl statefulRuleInfo = new StatefulRuleInfoImpl(ruleInfo, false, true);
message = ruleService.executeStatefulRules( statefulRuleInfo, message );
assertEquals( 20.0, order.getDiscount(), 0 );
assertEquals( "20%" ,message.getBody().get("DiscountObject"));
// process message again with a counter instance
objectList = new ObjectMapper().createObjectList(message, messagePathList);
ruleInfo = new RuleInfoBuilder("JBossESBPricingRulesStateful.drl").reload(true).globals(globals).defaultFacts(objectList).build();
statefulRuleInfo = new StatefulRuleInfoImpl(ruleInfo, false, true);
message = ruleService.continueStatefulRulesExecution( statefulRuleInfo, message );
Counter counter = (Counter) message.getBody().get("Counter");
assertEquals( 2 , counter.getCounter() );
}
@Test
public void continueSessionWithEntryPoint() throws RuleServiceException, ObjectMappingException, InterruptedException
{
Message message = createMessageWithOrder(order);
long timestamp = System.currentTimeMillis();
message.getProperties().setProperty(Environment.MESSAGE_ENTRY_TIME, timestamp);
final RuleInfoBuilder builder = new RuleInfoBuilder("PricingRulesStatefulEntryPoint.drl");
builder.global("message", message);
final ObjectMapper objectMapper = new ObjectMapper();
builder.defaultFact(objectMapper.getObjectFromMessage(message, "body.Counter"));
builder.defaultFact(message);
// OrderEntryPoint that matches the entry-point name in PricingRulesStatfulEntryPoint.drl.
builder.fact("OrderEntryPoint", objectMapper.getObjectFromMessage(message, "body.Order"));
// process message
StatefulRuleInfo statefulInfo = new StatefulRuleInfoImpl(builder.build(), false, true);
message = ruleService.executeStatefulRules(statefulInfo, message);
assertEquals( 20.0, order.getDiscount(), 0 );
assertEquals( "20%" ,message.getBody().get("DiscountObject"));
}
@Test (expected = RuleServiceException.class)
public void shouldThrowIfEntryPointDoesNotExistInSession() throws RuleServiceException, ObjectMappingException
{
Message message = createMessageWithOrder( order );
long timestamp = System.currentTimeMillis();
message.getProperties().setProperty(Environment.MESSAGE_ENTRY_TIME, timestamp);
final ArrayList<String> messagePathList = new ArrayList<String>();
messagePathList.add("body.Order");
messagePathList.add("body.Counter");
final RuleInfoBuilder builder = new RuleInfoBuilder("PricingRulesStatefulEntryPoint.drl");
builder.global("message", message);
final ObjectMapper objectMapper = new ObjectMapper();
builder.defaultFact(objectMapper.getObjectFromMessage(message, "body.Counter"));
// Non Existing entry-point name.
builder.fact("Bajja", objectMapper.getObjectFromMessage(message, "body.Order"));
// process message
StatefulRuleInfo statefulInfo = new StatefulRuleInfoImpl(builder.build(), true, false);
ruleService.executeStatefulRules(statefulInfo, message);
}
// Test setup methods
@Before
public void setup() throws RuleServiceException
{
RuleInfo ruleInfo = new RuleInfoBuilder("JBossESBRules.drl").reload(true).build();
ruleBaseState = ruleService.getRuleBaseStateForFileBasedRules(ruleInfo);
message = MessageFactory.getInstance().getMessage();
order = new Order();
order.setQuantity(20);
order.setUnitPrice( new BigDecimal("20.0") );
messagePathList = new ArrayList<String>();
messagePathList.add("body.Order");
messagePathList.add("body.Counter");
}
public static junit.framework.Test suite()
{
return new JUnit4TestAdapter( DroolsRuleServiceUnitTest.class );
}
@SuppressWarnings("unchecked")
private ArrayList<String> getDestinations( final Map<String,Object> globals )
{
return (ArrayList<String>) globals.get( "destinations" );
}
private Map<String,Object> getGlobalsWithDestAndMessage()
{
Map<String,Object> globals = getGlobalsWithDest();
globals.putAll( getGlobalsWithMessage( message ));
return globals;
}
private Map<String,Object> getGlobalsWithDest()
{
Map<String,Object> globals = new HashMap<String,Object>();
ArrayList<String> destinations = new ArrayList<String>();
globals.put("destinations", destinations );
return globals;
}
private Map<String,Object> getGlobalsWithMessage( final Message message )
{
Map<String,Object> globals = new HashMap<String,Object>();
globals.put("message", message );
return globals;
}
private Message createMessageWithOrder( final Order order )
{
Message message = MessageFactory.getInstance().getMessage(MessageType.JAVA_SERIALIZED);
message.getBody().add("Order", order);
return message;
}
}