package com.yahoo.dtf.actions.event; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.Map.Entry; import com.yahoo.dtf.actions.Action; import com.yahoo.dtf.actions.conditionals.Condition; import com.yahoo.dtf.config.Config; import com.yahoo.dtf.exception.DTFException; import com.yahoo.dtf.query.QueryIntf; /** * @dtf.tag compare * * @dtf.since 1.0 * @dtf.author Rodney Gomes * * @dtf.tag.desc The compare tag is used to compare events from different event * files that contain related data. Such as the event file from * writing data to a service and the event file from reading that * same data from the service. There has to be a way to relate * the data from both event files, either with a sequence id, * record id, etc. Once you're able to identify that two events * are relevant to the same data then you can use the validate * child tag of compare to validate what needs to be similar or * equal in order for these two events to be correct. * <br/><br/> * <b> * Be aware that this tag is still experimental and is going to * suffer some changes soon. These will be focused on making the * tag more efficient but may require more drastic changes to * the way the tag is used. * </b> * <br/><br/> * * @dtf.tag.example * <compare> * <query uri="storage://OUTPUT/compare_write_data.txt" * event="write.event" * cursor="c1"> * <select> * <field name="recordid"/> * <field name="data"/> * </select> * </query> * * <query uri="storage://OUTPUT/compare_read_data.txt" * event="read.event" * cursor="c2"> * <select> * <field name="recordid"/> * <field name="data"/> * </select> * </query> * * <where><eq op1="${c1.recordid}" op2="${c2.recordid}"/></where> * * <validate> * <assert><eq op1="${c1.data}" op2="${c2.data}"/></assert> * </validate> * </compare> * * @dtf.tag.example * <compare> * <query uri="storage://OUTPUT/read_data.txt" * event="write.event" * cursor="c1"/> * <!-- We know that our data was generated in a certain way based on a * sequence ID that we used so we can easily validate our read data * without the original data to validate against and instead using the * attributes from the event --> * <validate> * <if> * <neq op1="${c1.data}" * op2="${dtf.stream(random,${c1.size},${c1.recordid})}"/> * <then> * <log level="warn"> * Data was not equal!!! For recordid [${recordid}] * </log> * </then> * </if> * </validate> * </compare> * */ public class Compare extends Action { public Compare() { } public void execute() throws DTFException { ArrayList<Query> query = findActions(Query.class); Validate validate = (Validate) findFirstAction(Validate.class); Where where = (Where) findFirstAction(Where.class); if ( query.size() == 1 ) { /* * Simple iteration through the data and comparing it with a easily * re-generated data. */ Query first = query.get(0); QueryIntf fquery = Query.getQueryIntf(first); Config config = getConfig(); HashMap<String, String> outtermap = null; while ( (outtermap = fquery.next(false)) != null ) { Iterator<Entry<String,String>> entries = outtermap.entrySet().iterator(); while ( entries.hasNext() ) { Entry<String,String> entry = entries.next(); config.setProperty(entry.getKey(),entry.getValue()); } validate.execute(); } } else if ( query.size() == 2) { Query first = query.get(0); Query second = query.get(1); QueryIntf fquery = Query.getQueryIntf(first); QueryIntf squery = Query.getQueryIntf(second); Condition condition = (Condition) where.findFirstAction(Condition.class); Config config = getConfig(); HashMap<String, String> outtermap = null; while ( (outtermap = fquery.next(false)) != null ) { Iterator<Entry<String,String>> entries = outtermap.entrySet().iterator(); while ( entries.hasNext() ) { Entry<String,String> entry = entries.next(); config.setProperty(entry.getKey(),entry.getValue()); } long maxreset = squery.getResetCount()+2; HashMap<String, String> innermap = null; while ( (innermap = squery.next(true)) != null ) { entries = innermap.entrySet().iterator(); while ( entries.hasNext() ) { Entry<String,String> entry = entries.next(); config.setProperty(entry.getKey(),entry.getValue()); } if ( condition.evaluate() ) break; if ( squery.getResetCount() > maxreset ) { throw new DTFException("Unable to satisfy the where clause " + "and find the next correct event."); } } validate.execute(); } } else { throw new DTFException("You need 1-2 query elements in order to use this tag."); } } }