Package org.drools.testframework

Source Code of org.drools.testframework.ScenarioRunner$Populate

package org.drools.testframework;

import static org.mvel2.MVEL.eval;

import java.util.*;

import org.drools.FactHandle;
import org.drools.RuleBase;
import org.drools.base.ClassTypeResolver;
import org.drools.base.TypeResolver;
import org.drools.common.InternalRuleBase;
import org.drools.common.InternalWorkingMemory;
import org.drools.guvnor.client.modeldriven.testing.ExecutionTrace;
import org.drools.guvnor.client.modeldriven.testing.Expectation;
import org.drools.guvnor.client.modeldriven.testing.FactData;
import org.drools.guvnor.client.modeldriven.testing.FieldData;
import org.drools.guvnor.client.modeldriven.testing.Fixture;
import org.drools.guvnor.client.modeldriven.testing.RetractFact;
import org.drools.guvnor.client.modeldriven.testing.Scenario;
import org.drools.guvnor.client.modeldriven.testing.VerifyFact;
import org.drools.guvnor.client.modeldriven.testing.VerifyField;
import org.drools.guvnor.client.modeldriven.testing.VerifyRuleFired;
import org.drools.guvnor.server.util.ScenarioXMLPersistence;
import org.drools.rule.Package;
import org.drools.rule.TimeMachine;
import org.mvel2.MVEL;


/**
* This actually runs the test scenarios.
*
* @author Michael Neale
*
*/
public class ScenarioRunner {

  final Scenario scenario;
  final Map<String, Object> populatedData = new HashMap<String, Object>();
  final Map<String, Object> globalData = new HashMap<String, Object>();
  final Map<String, FactHandle> factHandles = new HashMap<String, FactHandle>();

  final InternalWorkingMemory workingMemory;


  /**
   * This constructor is normally used by Guvnor for running tests on a users request.
   * @param scenario
   *            The scenario to run.
   * @param resolver
   *            A populated type resolved to be used to resolve the types in
   *            the scenario.
   *
   * For info on how to invoke this, see
   * ContentPackageAssemblerTest.testPackageWithRuleflow in drools-guvnor 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 Scenario scenario, final TypeResolver resolver,
      final InternalWorkingMemory wm) throws ClassNotFoundException {
    this.scenario = scenario;
    this.workingMemory = wm;
    runScenario(scenario, resolver, wm);
  }

  /**
   * Use this constructor if you have a scenario in a file, for instance.
   * @throws ClassNotFoundException
   */
  public ScenarioRunner(String xml, RuleBase rb) throws ClassNotFoundException {
    this.scenario = ScenarioXMLPersistence.getInstance().unmarshal(xml);
    this.workingMemory = (InternalWorkingMemory) rb.newStatefulSession();
    Package pk = rb.getPackages()[0];
        ClassLoader cl = ((InternalRuleBase) rb).getRootClassLoader();
        HashSet<String> imports = new HashSet<String>();
        imports.add(pk.getName() + ".*");
        imports.addAll(pk.getImports().keySet());
        TypeResolver resolver = new ClassTypeResolver( imports, cl );
        runScenario(scenario, resolver, this.workingMemory);
  }

    interface Populate {
        public void go();
    }

  private void runScenario(final Scenario scenario,
      final TypeResolver resolver, final InternalWorkingMemory wm)
      throws ClassNotFoundException {
    MVEL.COMPILER_OPT_ALLOW_NAKED_METH_CALL = true;
    scenario.lastRunResult = new Date();
    //stub out any rules we don't want to have the consequences firing of.
    HashSet<String> ruleList = new HashSet<String>();
    ruleList.addAll(scenario.rules);
    //TestingEventListener.stubOutRules(ruleList, wm.getRuleBase(), scenario.inclusive);

    TestingEventListener listener = null;

        List<Populate> toPopulate = new ArrayList<Populate>();

    for (Iterator iterator = scenario.globals.iterator(); iterator.hasNext();) {
      final FactData fact = (FactData) iterator.next();
      final Object f = eval("new " + getTypeName(resolver, fact) + "()");
            toPopulate.add(new Populate() {
                public void go() {
                    populateFields(fact, globalData, f);
                }
            });
      globalData.put(fact.name, f);
      wm.setGlobal(fact.name, f);
    }

        doPopulate(toPopulate);

    for (Iterator<Fixture> iterator = scenario.fixtures.iterator(); iterator.hasNext();) {
      Fixture fx = iterator.next();

      if (fx instanceof FactData) {
        //deal with facts and globals
        final FactData fact = (FactData)fx;
        final Object f = (fact.isModify)? this.populatedData.get(fact.name) : eval("new " + getTypeName(resolver, fact) + "()");
        if (fact.isModify) {
          if (!this.factHandles.containsKey(fact.name)) {
            throw new IllegalArgumentException("Was not a previously inserted fact. [" + fact.name  + "]");
          }
                    toPopulate.add(new Populate() {
                        public void go() {
                            populateFields(fact, populatedData, f);
                            workingMemory.update(factHandles.get(fact.name), f);
                        }
                    });
        } else /* a new one */ {
                    populatedData.put(fact.name, f);
                    toPopulate.add(new Populate() {
                        public void go() {
                            populateFields(fact, populatedData, f);
                            factHandles.put(fact.name, wm.insert(f));
                        }
                    });
        }
      } else if (fx instanceof RetractFact) {
        RetractFact f = (RetractFact)fx;
        this.workingMemory.retract(this.factHandles.get(f.name));
        this.populatedData.remove(f.name);
      } else if (fx instanceof ExecutionTrace) {
                doPopulate(toPopulate);
        ExecutionTrace executionTrace = (ExecutionTrace)fx;
        //create the listener to trace rules

        if (listener != null) wm.removeEventListener(listener); //remove the old
        listener = new TestingEventListener();

        wm.addEventListener(listener);

        //set up the time machine
        applyTimeMachine(wm, executionTrace);

        //love you
        long time = System.currentTimeMillis();
        wm.fireAllRules(listener.getAgendaFilter(ruleList, scenario.inclusive),scenario.maxRuleFirings);
        executionTrace.executionTimeResult = System.currentTimeMillis() - time;
        executionTrace.numberOfRulesFired = listener.totalFires;
        executionTrace.rulesFired = listener.getRulesFiredSummary();


      } else if (fx instanceof Expectation) {
                doPopulate(toPopulate);
          Expectation assertion = (Expectation) fx;
          if (assertion instanceof VerifyFact) {
            verify((VerifyFact) assertion);
          } else if (assertion instanceof VerifyRuleFired) {
            verify((VerifyRuleFired) assertion,
                (listener.firingCounts != null) ? listener.firingCounts : new HashMap<String, Integer>());
          }
      } else {
        throw new IllegalArgumentException("Not sure what to do with " + fx);
      }



    }
       
        doPopulate(toPopulate);
  }

    private void doPopulate(List<Populate> toPopulate) {
        for (Populate p : toPopulate) {p.go();}
        toPopulate.clear();
    }

    private String getTypeName(TypeResolver resolver, FactData fact) throws ClassNotFoundException {

        String fullName = resolver.getFullTypeName(fact.type);
        if (fullName.equals("java.util.List") || fullName.equals("java.util.Collection")) {
                return "java.util.ArrayList";
        } else {
                return fullName;
        }
    }

    private void applyTimeMachine(final InternalWorkingMemory wm,
      ExecutionTrace executionTrace) {
    if (executionTrace.scenarioSimulatedDate != null) {
      final Calendar now = Calendar.getInstance();
      now.setTimeInMillis(executionTrace.scenarioSimulatedDate.getTime());
      wm.setTimeMachine(new TimeMachine() {
        @Override
        public Calendar getNow() {
          return now;
        }
      });
    } else {
      //normal time.
      wm.setTimeMachine(new TimeMachine());
    }
  }

  void verify(VerifyRuleFired assertion, Map<String, Integer> firingCounts) {

    assertion.actualResult = firingCounts.containsKey(assertion.ruleName) ? firingCounts
        .get(assertion.ruleName)
        : 0;
    if (assertion.expectedFire != null) {
      if (assertion.expectedFire) {
        if (assertion.actualResult > 0) {
          assertion.successResult = true;
          assertion.explanation = "Rule [" + assertion.ruleName + "] was actived " + assertion.actualResult + " times.";
        } else {
          assertion.successResult = false;
          assertion.explanation = "Rule [" + assertion.ruleName + "] was not activated. Expected it to be activated.";
        }
      } else {
        if (assertion.actualResult == 0) {
          assertion.successResult = true;
          assertion.explanation = "Rule [" + assertion.ruleName + "] was not activated.";
        } else {
          assertion.successResult = false;
          assertion.explanation = "Rule [" + assertion.ruleName + "] was activated " + assertion.actualResult + " times, but expected none.";
        }
      }
    }

    if (assertion.expectedCount != null) {
      if (assertion.actualResult.equals(assertion.expectedCount)) {
        assertion.successResult = true;
        assertion.explanation = "Rule [" + assertion.ruleName + "] activated " + assertion.actualResult + " times.";
      } else {
        assertion.successResult = false;
        assertion.explanation = "Rule [" + assertion.ruleName + "] activated " + assertion.actualResult + " times. Expected " + assertion.expectedCount + " times.";
      }
    }
  }


  void verify(VerifyFact value) {


    if (!value.anonymous) {
      Object fact = this.populatedData.get(value.name);
      if (fact == null) fact = this.globalData.get(value.name);
      checkFact(value, fact);
    } else {
      Iterator obs = this.workingMemory.iterateObjects();
      while(obs.hasNext()) {
        Object fact = obs.next();
        if (fact.getClass().getSimpleName().equals(value.name)) {
          checkFact(value, fact);
          if (value.wasSuccessful()) return;
        }
      }
      for (Iterator iterator = value.fieldValues.iterator(); iterator.hasNext();) {
        VerifyField vfl = (VerifyField) iterator.next();
        if (vfl.successResult == null) {
          vfl.successResult = Boolean.FALSE;
          vfl.actualResult = "No match";
        }
      }
     }
  }

  private void checkFact(VerifyFact value, Object fact) {
    for (int i = 0; i < value.fieldValues.size(); i++) {
      VerifyField fld = (VerifyField) value.fieldValues.get(i);
      Map<String, Object> st = new HashMap<String, Object>();
      st.put("__fact__", fact);
      if (fld.expected != null) {
        Object expectedVal = fld.expected.trim();
        if (fld.expected.startsWith("=")) {
          expectedVal = eval(fld.expected.substring(1), this.populatedData);
        }
        st.put("__expected__", expectedVal);

        fld.successResult = (Boolean) eval("__fact__." + fld.fieldName
            + " " + fld.operator  + " __expected__", st);


        if (!fld.successResult) {
          Object actual = eval("__fact__." + fld.fieldName, st);
          fld.actualResult = (actual != null) ? actual.toString() : "";

          if (fld.operator.equals("==")) {
            fld.explanation = "[" + value.name + "] field [" + fld.fieldName + "] was [" + fld.actualResult
                      + "] expected [" + fld.expected + "].";
          } else {
            fld.explanation = "[" + value.name + "] field [" + fld.fieldName + "] was not expected to be [" + fld.actualResult
            + "].";
          }
        } else {
          if (fld.operator.equals("==")) {
            fld.explanation = "[" + value.name + "] field [" + fld.fieldName + "] was [" + fld.expected + "].";
          } else if (fld.operator.equals("!=")){
            fld.explanation = "[" + value.name + "] field [" + fld.fieldName + "] was not [" + fld.expected + "].";
          }
        }
      }

    }
  }



  Object populateFields(FactData fact, Map<String, Object> factData, Object factObject) {
    for (int i = 0; i < fact.fieldData.size(); i++) {
      FieldData field = (FieldData) fact.fieldData.get(i);
      Object val;
      if (field.value != null && !field.value.equals("")) {
        if (field.value.startsWith("=")) {
          // eval the val into existence
          val = eval(field.value.substring(1), factData);
        } else {
          val = field.value;
        }
        Map<String, Object> vars = new HashMap<String, Object>();
        vars.putAll(factData);
        vars.put("__val__", val);
        vars.put("__fact__", factObject);
        eval("__fact__." + field.name + " = __val__", vars);
      }
    }
    return factObject;
  }

  /**
   * True if the scenario was run with 100% success.
   */
  public boolean wasSuccess() {
    return this.scenario.wasSuccessful();
  }

  /**
   * @return A pretty printed report detailing any failures that occured
   * when running the scenario (unmet expectations).
   */
  public String getReport() {
    return this.scenario.printFailureReport();
  }


}
TOP

Related Classes of org.drools.testframework.ScenarioRunner$Populate

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