/* * Copyright 2010 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. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.drools.workbench.models.testscenarios.backend; import java.lang.reflect.InvocationTargetException; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.drools.core.base.ClassTypeResolver; import org.drools.core.impl.InternalKnowledgeBase; import org.drools.workbench.models.testscenarios.backend.populators.FactPopulator; import org.drools.workbench.models.testscenarios.backend.populators.FactPopulatorFactory; import org.drools.workbench.models.testscenarios.shared.ActivateRuleFlowGroup; import org.drools.workbench.models.testscenarios.shared.CallMethod; import org.drools.workbench.models.testscenarios.shared.ExecutionTrace; import org.drools.workbench.models.testscenarios.shared.Expectation; import org.drools.workbench.models.testscenarios.shared.FactData; import org.drools.workbench.models.testscenarios.shared.Fixture; import org.drools.workbench.models.testscenarios.shared.RetractFact; import org.drools.workbench.models.testscenarios.shared.Scenario; import org.kie.api.KieBase; import org.kie.api.runtime.KieSession; import org.mvel2.MVEL; /** * This actually runs the test scenarios. */ public class ScenarioRunner { private final KieSession ksession; private final int maximumAmountOfRuleFirings; private TestScenarioKSessionWrapper workingMemoryWrapper; private FactPopulatorFactory factPopulatorFactory; private FactPopulator factPopulator; /** * This constructor is normally used by Guvnor for running tests on a users * request. * @param ksession A populated type resolved to be used to resolve the types in * the scenario. * <p/> * For info on how to invoke this, see * ContentPackageAssemblerTest.testPackageWithRuleflow in * guvnor-webapp This requires that the classloader for the * thread context be set appropriately. The PackageBuilder can * provide a suitable TypeResolver for a given package header, * and the Package config can provide a classloader. */ public ScenarioRunner( final KieSession ksession ) throws ClassNotFoundException { this( ksession, 0 ); } /** * @param ksession A populated type resolved to be used to resolve the types in * the scenario. * @param maximumAmountOfRuleFirings Limit for amount of rules that can fire. To prevent infinite loops. * @throws ClassNotFoundException */ public ScenarioRunner( final KieSession ksession, final int maximumAmountOfRuleFirings ) throws ClassNotFoundException { this.ksession = ksession; this.maximumAmountOfRuleFirings = maximumAmountOfRuleFirings; } public void run( final Scenario scenario ) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, InvalidClockTypeException { final Map<String, Object> populatedData = new HashMap<String, Object>(); final Map<String, Object> globalData = new HashMap<String, Object>(); // This looks safe! final KieBase kieBase = ksession.getKieBase(); final ClassLoader classloader2 = ( (InternalKnowledgeBase) kieBase ).getRootClassLoader(); final ClassTypeResolver resolver = new ClassTypeResolver( getImports( scenario ), classloader2 ); this.workingMemoryWrapper = new TestScenarioKSessionWrapper( ksession, resolver, populatedData, globalData, scenarioUsesTimeWalk(scenario)); this.factPopulatorFactory = new FactPopulatorFactory( populatedData, globalData, resolver ); this.factPopulator = new FactPopulator( ksession, populatedData ); MVEL.COMPILER_OPT_ALLOW_NAKED_METH_CALL = true; scenario.setLastRunResult( new Date() ); populateGlobals( scenario.getGlobals() ); applyFixtures( scenario.getFixtures(), createScenarioSettings( scenario ) ); } private boolean scenarioUsesTimeWalk(Scenario scenario) { for (Fixture fixture : scenario.getFixtures()) { if (fixture instanceof ExecutionTrace) { if (((ExecutionTrace) fixture).getScenarioSimulatedDate() != null) { return true; } } } return false; } private Set<String> getImports( final Scenario scenario ) { final Set<String> imports = new HashSet<String>(); imports.addAll( scenario.getImports().getImportStrings() ); if ( scenario.getPackageName() != null && !scenario.getPackageName().isEmpty() ) { imports.add( scenario.getPackageName() + ".*" ); } return imports; } private ScenarioSettings createScenarioSettings( final Scenario scenario ) { final ScenarioSettings scenarioSettings = new ScenarioSettings(); scenarioSettings.setRuleList( scenario.getRules() ); scenarioSettings.setInclusive( scenario.isInclusive() ); scenarioSettings.setMaxRuleFirings( getMaxRuleFirings( scenario ) ); return scenarioSettings; } private int getMaxRuleFirings( final Scenario scenario ) { if ( maximumAmountOfRuleFirings <= 0 ) { return scenario.getMaxRuleFirings(); } else { return maximumAmountOfRuleFirings; } } private void applyFixtures(final List<Fixture> fixtures, final ScenarioSettings scenarioSettings) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, InvalidClockTypeException { for ( Iterator<Fixture> iterator = fixtures.iterator(); iterator.hasNext(); ) { Fixture fixture = iterator.next(); if ( fixture instanceof FactData ) { factPopulator.add( factPopulatorFactory.createFactPopulator( (FactData) fixture ) ); } else if ( fixture instanceof RetractFact ) { factPopulator.retractFact( ( (RetractFact) fixture ).getName() ); } else if ( fixture instanceof CallMethod ) { workingMemoryWrapper.executeMethod( (CallMethod) fixture ); } else if ( fixture instanceof ActivateRuleFlowGroup ) { workingMemoryWrapper.activateRuleFlowGroup( ( (ActivateRuleFlowGroup) fixture ).getName() ); } else if ( fixture instanceof ExecutionTrace ) { factPopulator.populate(); workingMemoryWrapper.executeSubScenario( (ExecutionTrace) fixture, scenarioSettings ); } else if ( fixture instanceof Expectation ) { factPopulator.populate(); workingMemoryWrapper.verifyExpectation( (Expectation) fixture ); } else { throw new IllegalArgumentException( "Not sure what to do with " + fixture ); } } factPopulator.populate(); } private void populateGlobals( final List<FactData> globals ) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException { for ( final FactData fact : globals ) { factPopulator.add( factPopulatorFactory.createGlobalFactPopulator( fact ) ); } factPopulator.populate(); } }