Re-work Transaction Controller so original behaviour is the default

git-svn-id: https://svn.apache.org/repos/asf/jakarta/jmeter/branches/rel-2-2@554438 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Sebastian Bazley 2007-07-08 20:46:03 +00:00
parent 0c86eada81
commit 9efb5971c6
5 changed files with 168 additions and 16 deletions

View File

@ -20,23 +20,76 @@ package org.apache.jmeter.control;
import java.io.Serializable;
import org.apache.jmeter.samplers.SampleEvent;
import org.apache.jmeter.samplers.SampleListener;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.samplers.Sampler;
import org.apache.jmeter.testelement.property.BooleanProperty;
import org.apache.jmeter.threads.JMeterContext;
import org.apache.jmeter.threads.JMeterThread;
import org.apache.jmeter.threads.JMeterVariables;
import org.apache.jmeter.threads.ListenerNotifier;
import org.apache.jmeter.threads.SamplePackage;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;
/**
* Transaction Controller to measure transaction times
*
* There are two different modes for the controller:
* - generate additional total sample after nested samples (as in JMeter 2.2)
* - generate parent sampler containing the nested samples
*
*/
public class TransactionController extends GenericController implements Controller, Serializable {
public class TransactionController extends GenericController implements SampleListener, Controller, Serializable {
private static final Logger log = LoggingManager.getLoggerForClass();
transient private TransactionSampler transactionSampler;
transient private ListenerNotifier lnf;
transient private SampleResult res;
transient private int calls;
transient private int noFailingSamples;
private static final String PARENT = "TransactionController.parent";// $NON-NLS-1$
/**
* Creates a Transaction Controller
*/
public TransactionController() {
lnf = new ListenerNotifier();
}
private Object readResolve(){
lnf = new ListenerNotifier();
return this;
}
public void setParent(boolean _parent){
setProperty(new BooleanProperty(PARENT, _parent));
}
public boolean isParent(){
return getPropertyAsBoolean(PARENT);
}
public Sampler next(){
if (isParent()){
return next1();
} else {
return next2();
}
}
///////////////// Transaction Controller - parent ////////////////
/**
* @see org.apache.jmeter.control.Controller#next()
*/
public Sampler next() {
public Sampler next1() {
// Check if transaction is done
if(transactionSampler != null && transactionSampler.isTransactionDone()) {
if (log.isDebugEnabled()) {
@ -67,6 +120,9 @@ public class TransactionController extends GenericController implements Controll
}
protected Sampler nextIsAController(Controller controller) throws NextIsNullException {
if (!isParent()) {
return super.nextIsAController(controller);
}
Sampler returnValue;
Sampler sampler = controller.next();
if (sampler == null) {
@ -80,4 +136,74 @@ public class TransactionController extends GenericController implements Controll
}
return returnValue;
}
////////////////////// Transaction Controller - additional sample //////////////////////////////
public Sampler next2() {
if (isFirst()) // must be the start of the subtree
{
calls = 0;
noFailingSamples = 0;
res = new SampleResult();
res.setSampleLabel(getName());
// Assume success
res.setSuccessful(true);
res.sampleStart();
}
Sampler returnValue = super.next();
if (returnValue == null) // Must be the end of the controller
{
if (res != null) {
res.sampleEnd();
res.setResponseMessage("Number of samples in transaction : " + calls + ", number of failing samples : " + noFailingSamples);
if(res.isSuccessful()) {
res.setResponseCodeOK();
}
// TODO could these be done earlier (or just once?)
JMeterContext threadContext = getThreadContext();
JMeterVariables threadVars = threadContext.getVariables();
SamplePackage pack = (SamplePackage) threadVars.getObject(JMeterThread.PACKAGE_OBJECT);
if (pack == null) {
log.warn("Could not fetch SamplePackage");
} else {
SampleEvent event = new SampleEvent(res, getName());
// We must set res to null now, before sending the event for the transaction,
// so that we can ignore that event in our sampleOccured method
res = null;
lnf.notifyListeners(event, pack.getSampleListeners());
}
}
}
else {
// We have sampled one of our children
calls++;
}
return returnValue;
}
public void sampleOccurred(SampleEvent se) {
if (!isParent()) {
// Check if we are still sampling our children
if(res != null) {
SampleResult sampleResult = se.getResult();
res.setThreadName(sampleResult.getThreadName());
res.setBytes(res.getBytes() + sampleResult.getBytes());
if(!sampleResult.isSuccessful()) {
res.setSuccessful(false);
noFailingSamples++;
}
}
}
}
public void sampleStarted(SampleEvent e) {
}
public void sampleStopped(SampleEvent e) {
}
}

View File

@ -18,16 +18,21 @@
package org.apache.jmeter.control.gui;
import java.awt.BorderLayout;
import javax.swing.JCheckBox;
import org.apache.jmeter.control.TransactionController;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.gui.layout.VerticalLayout;
/**
* A Transaction controller component.
*
*/
public class TransactionControllerGui extends AbstractControllerGui {
private JCheckBox parent; // If selected, then generate parent sample, otherwise as per original controller
/**
* Create a new TransactionControllerGui instance.
*/
@ -42,9 +47,15 @@ public class TransactionControllerGui extends AbstractControllerGui {
return lc;
}
public void configure(TestElement el) {
super.configure(el);
parent.setSelected(((TransactionController) el).isParent());
}
/* Implements JMeterGUIComponent.modifyTestElement(TestElement) */
public void modifyTestElement(TestElement el) {
configureTestElement(el);
((TransactionController) el).setParent(parent.isSelected());
}
public String getLabelResource() {
@ -55,8 +66,10 @@ public class TransactionControllerGui extends AbstractControllerGui {
* Initialize the GUI components and layout for this component.
*/
private void init() {
setLayout(new BorderLayout());
setLayout(new VerticalLayout(5, VerticalLayout.BOTH, VerticalLayout.TOP));
setBorder(makeBorder());
add(makeTitlePanel(), BorderLayout.NORTH);
add(makeTitlePanel());
parent = new JCheckBox(JMeterUtils.getResString("transaction_controller_parent")); // $NON-NLS-1$
add(parent);
}
}

View File

@ -743,6 +743,7 @@ throughput_control_title=Throughput Controller
throughput_control_tplabel=Throughput
time_format=Format string for SimpleDateFormat (optional)
timelim=Time limit
transaction_controller_parent=Generate parent sample
transaction_controller_title=Transaction Controller
unbind=Thread Unbind
uniform_timer_delay=Constant Delay Offset (in milliseconds)\:

View File

@ -42,7 +42,7 @@ Some of the main enhancements are:
<li>__V() function allows support of nested variable references</li>
<li>LDAP Ext sampler optionally parses result sets and supports secure mode</li>
<li>FTP Sampler supports Ascii/Binary mode and upload</li>
<li>Transaction Controller now generates Sample with subresults</li>
<li>Transaction Controller now optionally generates a Sample with subresults</li>
<li>HTTPS session contexts are now per-thread, rather than shared. This gives better emulation of multiple users</li>
<li>BeanShell elements now support ThreadListener and TestListener interfaces</li>
<li>Coloured icons in Tree View Listener and elsewhere to better differentiate failed samples.</li>
@ -58,6 +58,9 @@ The main bug fixes are:
<li>Test elements no longer default to previous contents; test elements no longer cleared when changing language.</li>
</ul>
<h4>Known problems:</h4>
<p>Transaction Controller parent mode does not support nested Transaction Controllers.
Doing so may cause a Null Pointer Exception in TestCompiler.
</p>
<p>Thread active counts are always zero in CSV and XML files when running remote tests.
</p>
<p>The property file_format.testlog=2.1 is treated the same as 2.2.
@ -93,7 +96,6 @@ The HTTP Authorisation Manager now has extra columns for domain and realm,
so the temporary work-round of using '\' and '@' in the username to delimit the domain and realm
has been removed.
</p>
<p>The Transaction Controller no longer appears as a separate sample; it now includes its nested samples as subsamples</p>
<p>
Control-Z no longer used for Remote Start All - this now uses Control+Shift+R
</p>

View File

@ -1476,31 +1476,41 @@ the contents are used to prefix the pathname.
<component name="Transaction Controller" index="&sect-num;.2.15" width="358" height="131" screenshot="transactioncontroller.png">
<description>
<p>The Transaction Controller times how long it takes for all its children to run.
It then adds a "sample" entry to the test output with the total elapsed time.
The name of the element is used to name the "sample".
</p>
<p>
The Transaction Comntroller is used to group samplers by generating an additional
sample which totals the nested samples.
For JMeter versions after 2.3, there are two modes of operation
<ul>
<li>additional sample is added after the nested samples</li>
<li>additional sample is added as a parent of the nested samples</li>
</ul>
</p>
<p>
The generated sample time includes all the times for the nested samplers, and any timers etc.
Depending on the clock resolution, it may be slightly longer than the sum of the individual samplers plus timers.
The clock might tick after the controller recorded the start time but before the first sample starts.
Similarly at the end.
</p>
<p>For JMeter versions after 2.2, the controlled samples no longer appear as separate samples, but as subsamples.
Also the Transaction Sample is only regarded as successful if all its sub-samples are successful.
This is similar to the way the HTTP Samplers work when retrieving embedded objects (images etc).
The individual samples can still be seen in the Tree View Listener,
<p>The generated sample is only regarded as successful if all its sub-samples are successful.</p>
<p>
In parent mode, the individual samples can still be seen in the Tree View Listener,
but no longer appear as separate entries in other Listeners.
Also, the sub-samples do not appear in CSV log files, but they can be saved to XML files.
</p>
<note>
Assertions (etc) can be added to the Transaction Controller.
In parent mode, Assertions (etc) can be added to the Transaction Controller.
However by default they will be applied to both the individual samples and the overall transaction sample.
To limit the scope of the Assertions, use a Simple Controller to contain the samples, and add the Assertions
to the Simple Controller.
Parent mode controllers do not currently properly support nested transaction controllers of either type.
</note>
</description>
<properties>
<property name="Name" required="Yes">Descriptive name for this controller that is shown in the tree, and used to name the transaction.</property>
<property name="Generate Parent Sample" required="Yes">
If checked, then the sample is generated as a parent of the other samples,
otherwise the sample is generated as an independent sample.
</property>
</properties>
</component>