Bug 57730 - SampleEvent for TransactionSampler: isTransactionSampleEvent return false with parent mode
Summary: SampleEvent for TransactionSampler: isTransactionSampleEvent return false wi...
Status: NEW
Alias: None
Product: JMeter
Classification: Unclassified
Component: Main (show other bugs)
Version: 2.13
Hardware: All All
: P2 enhancement (vote)
Target Milestone: ---
Assignee: JMeter issues mailing list
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-03-20 05:49 UTC by Myoung
Modified: 2015-07-01 07:02 UTC (History)
2 users (show)



Attachments
the gui design for my pacingtimer plugin. (37.20 KB, image/png)
2015-03-20 05:49 UTC, Myoung
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Myoung 2015-03-20 05:49:14 UTC
Created attachment 32588 [details]
the gui design for my pacingtimer plugin.

With parent mode on TransactionCotroller. 
The isTransactionSampleEvent() on SampleEvent object always returns "false" even with TransactionSampler. 
Please make it return "TRUE" with TransactionSampler not only “non parent mode” but also “parent mode”

Reason) I am trying the develop the PacingTimer(similar functionality which is provided by commercial testing tools), and i want to define the target mode of “Iteration”, “Transaction” and “Sampler” to which applying the pacing time since many of people is familiar with Transaction pacing and Iteration pacing too. To implement this “Transaction mode” requirement, I need a way to say whether it is parent mode or not. 
I could modify the JmeterThread codes as below, however I never wants to touch the JMeter released build. 

Here what I tested for my requset, I had to change couple of code of JmeterThread.java
<<<original>>>>
(method : process_sampler)
if(transactionSampler != null) {
	:
notifyListeners(transactionPack.getSampleListeners(), transactionResult);
:
}
(mdthod notifyListeners)
SampleEvent event = new SampleEvent(result, threadGroup.getName(), threadVars);
notifier.notifyListeners(event, listeners);

    private void notifyListeners(List<SampleListener> listeners, SampleResult result, boolean isTransactionSampleEvent) {
        SampleEvent event = new SampleEvent(result, threadGroup.getName(), threadVars,isTransactionSampleEvent);
        notifier.notifyListeners(event, listeners);

    }
<<<<<changes .... >>>>
(method : process_sampler)
if(transactionSampler != null) {
	:
notifyListeners(transactionPack.getSampleListeners(), transactionResult, true);  //add parameter for transaction sampler
:
}
 (mdthod notifyListeners  )
private void notifyListeners(List<SampleListener> listeners, SampleResult result) {
    	notifyListeners(listeners,result,false);
    }

private void notifyListeners(List<SampleListener> listeners, SampleResult result, boolean isTransactionSampleEvent) {
      SampleEvent event = new SampleEvent(result, threadGroup.getName(), threadVars,isTransactionSampleEvent);
      notifier.notifyListeners(event, listeners);
    }



best regards
myoung
Comment 1 Philippe Mouawad 2015-03-22 18:13:50 UTC
Hello,
Thanks for your report, but it is not clear for me.
Could you provide a patch ?
Also I am requalifying it as enhancement as it is related to a potential new feature.
Maybe it would be better to rename it and provide the full patch for Pacing Timer.

Thanks
Regards
Comment 2 Myoung 2015-03-23 09:55:12 UTC
I have pasted the codes for my plugin(dynamic pacing time), at the moment this one works fine with 2.12 and 2.13 (excep the transaction parent mode). 

Am i attached the patch as  you asked? If not please let me know

best regards
myoung
<--- timer code.---------------->
package myoung.jmeter.timer;


import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.jmeter.engine.event.LoopIterationEvent;
import org.apache.jmeter.engine.event.LoopIterationListener;
import org.apache.jmeter.testbeans.TestBean;
import org.apache.jmeter.testelement.AbstractTestElement;
import org.apache.jmeter.testelement.TestStateListener;
import org.apache.jmeter.testelement.property.JMeterProperty;
import org.apache.jmeter.timers.Timer;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;
import org.apache.soap.providers.com.Log;
import org.apache.jmeter.threads.JMeterContextService;
import org.apache.jmeter.threads.JMeterVariables;
import org.apache.jmeter.control.TransactionSampler;
import org.apache.jmeter.samplers.SampleEvent;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.samplers.Sampler;
import org.apache.jmeter.samplers.SampleListener;


public class DynamicPacingTimer extends AbstractTestElement implements Timer, TestBean, SampleListener, LoopIterationListener {
// Timer excluded
//public class DynamicPacingTimer extends AbstractTestElement implements TestBean, SampleListener, LoopIterationListener {

	private static final long serialVersionUID = 7750524238843015040L;
	private static final Logger log = LoggingManager.getLoggerForClass();
    private long previousTime =0;//??double -> long
    private boolean isFirstIteration = true;
    private boolean isRandomMaxSet = false;
    // to calculate random timer
	private int randomMax; //will be used to calculate max
	private long pacingtimemin; //
	private java.util.Random randomgen = new java.util.Random();
	    
    private boolean delaySamploccured = false; 
    
    
    // fields on the gui
    private long pacingtime;
	private double percentmin;
	private double percentmax;
    private PacingMode  pacingmode; // = PacingMode.modeIteration; 
    public enum PacingMode {
        modeSampler("Pacingmode.1"),
        modeTransaction("Pacingmode.2"),
        modeIteration("Pacingmode.3"),
        ;
        private final String propertyName; 
        
        PacingMode(String  propertyName) {
        	this.propertyName = propertyName;
        }


        public String toString() {
            return propertyName;
        }
    }	//end of PacingMode

    
	public void setPacingtime(long pacingtime) {
		this.pacingtime = pacingtime;
	
	
	}
	
	public long  getPacingtime() {
    	return pacingtime;
	}    

	    
	public void setPercentmin(double percentmin) {
		this.percentmin = percentmin;
	
	}
	
	public double getPercentmin() {
    	return percentmin;
	}    

	public void setPercentmax(double percentmax) {
		this.percentmax = percentmax;
		
		if (! isRandomMaxSet) { //this logic must be stay on the last 
			this.pacingtimemin = this.pacingtime;
			double pacingtimemax = this.pacingtime;
			
			double tmpDouble; 
			if (this.percentmin > 0 ) { 
				tmpDouble =   this.pacingtime * ((100.0 - this.percentmin) / 100.0);
				this.pacingtimemin = (long)tmpDouble; 
			}
			if (this.percentmax > 0 )  {    
				pacingtimemax =  this.pacingtime * ((100.0 + this.percentmax) / 100.0);
			}
			this.randomMax = (int)( pacingtimemax - this.pacingtimemin);	
			
			log.debug("(pacingtime)"+ this.pacingtime +  " pacingmin:"+pacingtimemin + " randommax:" +this.randomMax );
			isRandomMaxSet = true;
		}
	}
	
	
	public double getPercentmax() {
    	return percentmax;
	}    

	public int getPacingmode() {
         return pacingmode.ordinal();
     }

     public void setPacingmode(int pacingmode) {
         this.pacingmode = PacingMode.values()[pacingmode];
     }

/*
 *     public int getCalcMode() {
        return mode.ordinal();
    }

    public void setCalcMode(int mode) {
        this.mode = Mode.values()[mode];
    }
 * 
 * */    
    
    public DynamicPacingTimer() {
    	
    }

    public long delay() {
        switch (pacingmode) {
        case modeSampler: //
        		calculateNdelay(JMeterContextService.getContext().getCurrentSampler().getName());//calculateNdelay( );
        default: 
            break;
        }	    	

    	return 0;
    
    }
    private void calculateNdelay() {
    	calculateNdelay("");
    }
    
    private void calculateNdelay(String label) {
    	long delay = 0 ;
    	long currentTime = System.currentTimeMillis();

    	//---- for debug
       // int minutes;
//    	java.util.Calendar cal; 
//        String currTimeString = "";
//        String prevTimeString = "";
//        cal = java.util.Calendar.getInstance();
//
//    	cal.setTimeInMillis(currentTime);     	//minutes = cal.get(java.util.Calendar.MINUTE);
//     	currTimeString =    new java.text.SimpleDateFormat("mm:ss.SSS").format(cal.getTime());
//        cal.setTimeInMillis(previousTime);     	//minutes = cal.get(java.util.Calendar.MINUTE);
//     	prevTimeString =    new java.text.SimpleDateFormat("mm:ss.SSS").format(cal.getTime());
     	//--- for debug (end)
     	long tmppacingtime = pacingtimemin;
     	if (randomMax > 0 ) {tmppacingtime = randomgen.nextInt(randomMax) + pacingtimemin;} 
     	
        long currentTarget = previousTime + tmppacingtime;
        if (currentTarget < currentTime  ) { 
            previousTime = currentTime; //no delay : // We're behind schedule
            delay = 0;
        } else {// response time is in the target time
        	previousTime = currentTarget; // calculate delay
        	delay = currentTarget - currentTime;
        }
                   
        //log.debug("   (__calculeateNdelay)prev:"  + prevTimeString + " now:"  + currTimeString + "  delay:" + delay  + "  pacing:" + tmppacingtime   + " :::" +currSampler.getName());    
        log.debug("   (__calculeateNdelay):"  + previousTime + " now:"  + currentTime + "  delay:" + delay  + "  pacing:" + tmppacingtime   + " :::" + label);    
        try { Thread.sleep(delay);  } catch (InterruptedException e) { }
        //return delay;

    	/*

        log.debug(Thread.currentThread().getStackTrace()[1].getMethodName()  +
        		" curr:" +  currSampler.getClass() +"_"+ currSampler.getName() );
        //log.debug(Thread.currentThread().getStackTrace()[1].getMethodName()  + " prev:" +  currSampler.getClass() +"_"+ currSampler.getName() );
    	System.out.println("    " + Thread.currentThread().getStackTrace()[1].getMethodName()  +  " curr:" +  currSampler.getClass() +"_"+ currSampler.getName());
        if ((currSampler instanceof TransactionSampler)) {
        } else {
        	//System.out.println ("         Not Transaction Sampler :" + prevSampler.getClass() +"_"+ currSampler.getClass()) ;
        }
    	
    	
    	long currentTime = System.currentTimeMillis();
        long currentTarget = previousTime;
        if (currentTime > currentTarget) {
            // We're behind schedule -- try to catch up:
            previousTime = currentTime; // assume the sample will run immediately
            return 0;
        }
        previousTime = currentTarget; // assume the sample will run as soon as the delay has expired
        //System.out.println(previousTime+ " " + currentTime + " " + (currentTarget - currentTime));
        return (long)(currentTarget - currentTime);
        */
    }
    
    
    private void reset() {
        previousTime = 0;
    }

    
    public String toString() {
        return "";
    }

    @Override
    public void setProperty(JMeterProperty property) {
        super.setProperty(property);
    }
    
  //---- LoopIterationListener : when iterartion(per thread group started)
    public void iterationStart(LoopIterationEvent iterEvent) {
    	if (isFirstIteration){
        	previousTime = System.currentTimeMillis();
    		isFirstIteration = false; 
    	}
        log.debug(Thread.currentThread().getStackTrace()[1].getMethodName()  
        		+ "------------> ITERATION"
		      //+" lastSample:"+  JMeterContextService.getContext().getVariables().get("JMeterThread.last_sample_ok")
        		+ "_"+ iterEvent.getSource().getName()  + "  count:" +  iterEvent.getIteration());
        switch (pacingmode) {
        case modeIteration: // Total number of threads
        	calculateNdelay(iterEvent.getSource().getName() );//calculateNdelay( );
        	
            break;
        default: 
            break;
        }		
    	
    }
    
    

    @Override
    // !! Transaction Parent mode: it is not invoked with samplers with non-partnet mode of transaction
    public void sampleOccurred(SampleEvent se) {
        //log.debug(Thread.currentThread().getStackTrace()[1].getMethodName() 
        //		+ "*isTranSampleEvent:" + se.isTransactionSampleEvent()//+ "_sampleDepth:" +  travleSampleEvent(se)
        //			);    	
        switch (pacingmode) {
        case modeTransaction: // It does not work with Transaction Parent mode
           	if (se.isTransactionSampleEvent() ) {
        		calculateNdelay(se.getResult().getSampleLabel()); //calculateNdelay( );
        	}
        case modeIteration: 
    		break;
        default: 
            break;
        }	    	
    	

    }

    @Override
    public void sampleStarted(SampleEvent e) {
        log.debug(Thread.currentThread().getStackTrace()[1].getMethodName());
    }

    @Override
    public void sampleStopped(SampleEvent e) {
        if (e.isTransactionSampleEvent() ) {
            log.debug(Thread.currentThread().getStackTrace()[1].getMethodName() + " TRANSACTION SAMPLE" );
        } else {
        	log.debug(Thread.currentThread().getStackTrace()[1].getMethodName() + "             SAMPLE" );
        }
    	
    }
   
}