Fix NPE when using nested Transaction Controllers with parent samples

git-svn-id: https://svn.apache.org/repos/asf/jakarta/jmeter/trunk@674210 13f79535-47bb-0310-9956-ffa450edef68

Former-commit-id: e5f3ecb5c7
This commit is contained in:
Sebastian Bazley 2008-07-05 16:48:57 +00:00
parent 3f920e2cb1
commit 9be8566a56
2 changed files with 126 additions and 99 deletions

View File

@ -237,104 +237,7 @@ public class JMeterThread implements Runnable, Serializable {
while (running) { while (running) {
Sampler sam; Sampler sam;
while (running && (sam = controller.next()) != null) { while (running && (sam = controller.next()) != null) {
try { process_sampler(sam, null);
threadContext.setCurrentSampler(sam);
// Check if we are running a transaction
TransactionSampler transactionSampler = null;
if(sam instanceof TransactionSampler) {
transactionSampler = (TransactionSampler) sam;
}
// Find the package for the transaction
SamplePackage transactionPack = null;
if(transactionSampler != null) {
transactionPack = compiler.configureTransactionSampler(transactionSampler);
// Check if the transaction is done
if(transactionSampler.isTransactionDone()) {
// Get the transaction sample result
SampleResult transactionResult = transactionSampler.getTransactionResult();
transactionResult.setThreadName(threadName);
transactionResult.setGroupThreads(threadGroup.getNumberOfThreads());
transactionResult.setAllThreads(JMeterContextService.getNumberOfThreads());
// Check assertions for the transaction sample
checkAssertions(transactionPack.getAssertions(), transactionResult);
// Notify listeners with the transaction sample result
notifyListeners(transactionPack.getSampleListeners(), transactionResult);
compiler.done(transactionPack);
// Transaction is done, we do not have a sampler to sample
sam = null;
}
else {
// It is the sub sampler of the transaction that will be sampled
sam = transactionSampler.getSubSampler();
}
}
// Check if we have a sampler to sample
if(sam != null) {
// Get the sampler ready to sample
SamplePackage pack = compiler.configureSampler(sam);
// Hack: save the package for any transaction controllers
threadVars.putObject(PACKAGE_OBJECT, pack);
delay(pack.getTimers());
Sampler sampler = pack.getSampler();
sampler.setThreadContext(threadContext);
sampler.setThreadName(threadName);
TestBeanHelper.prepare(sampler);
// Perform the actual sample
SampleResult result = sampler.sample(null);
// TODO: remove this useless Entry parameter
// If we got any results, then perform processing on the result
if (result != null) {
result.setGroupThreads(threadGroup.getNumberOfThreads());
result.setAllThreads(JMeterContextService.getNumberOfThreads());
result.setThreadName(threadName);
threadContext.setPreviousResult(result);
runPostProcessors(pack.getPostProcessors());
checkAssertions(pack.getAssertions(), result);
// Do not send subsamples to listeners which receive the transaction sample
List sampleListeners = getSampleListeners(pack, transactionPack, transactionSampler);
notifyListeners(sampleListeners, result);
compiler.done(pack);
// Add the result as subsample of transaction if we are in a transaction
if(transactionSampler != null) {
transactionSampler.addSubSamplerResult(result);
}
// Check if thread or test should be stopped
if (result.isStopThread() || (!result.isSuccessful() && onErrorStopThread)) {
stopThread();
}
if (result.isStopTest() || (!result.isSuccessful() && onErrorStopTest)) {
stopTest();
}
} else {
compiler.done(pack); // Finish up
}
}
if (scheduler) {
// checks the scheduler to stop the iteration
stopScheduler();
}
} catch (JMeterStopTestException e) {
log.info("Stopping Test: " + e.toString());
stopTest();
} catch (JMeterStopThreadException e) {
log.info("Stopping Thread: " + e.toString());
stopThread();
} catch (Exception e) {
if (sam != null) {
log.error("Error while processing sampler '"+sam.getName()+"' :", e);
} else {
log.error("", e);
}
}
} }
if (controller.isDone()) { if (controller.isDone()) {
running = false; running = false;
@ -360,6 +263,128 @@ public class JMeterThread implements Runnable, Serializable {
threadFinished(); threadFinished();
} }
} }
/**
* Process the current sampler, handling transaction samplers.
*
* @param current sampler
* @param parent sampler
* @return SampleResult if a transaction was processed
*/
private SampleResult process_sampler(Sampler current, Sampler parent) {
SampleResult transactionResult = null;
try {
threadContext.setCurrentSampler(current);
// Check if we are running a transaction
TransactionSampler transactionSampler = null;
if(current instanceof TransactionSampler) {
transactionSampler = (TransactionSampler) current;
}
// Find the package for the transaction
SamplePackage transactionPack = null;
if(transactionSampler != null) {
transactionPack = compiler.configureTransactionSampler(transactionSampler);
// Check if the transaction is done
if(transactionSampler.isTransactionDone()) {
// Get the transaction sample result
transactionResult = transactionSampler.getTransactionResult();
transactionResult.setThreadName(threadName);
transactionResult.setGroupThreads(threadGroup.getNumberOfThreads());
transactionResult.setAllThreads(JMeterContextService.getNumberOfThreads());
// Check assertions for the transaction sample
checkAssertions(transactionPack.getAssertions(), transactionResult);
// Notify listeners with the transaction sample result
if (!(parent instanceof TransactionSampler)){
notifyListeners(transactionPack.getSampleListeners(), transactionResult);
}
compiler.done(transactionPack);
// Transaction is done, we do not have a sampler to sample
current = null;
}
else {
Sampler prev = current;
// It is the sub sampler of the transaction that will be sampled
current = transactionSampler.getSubSampler();
if (current instanceof TransactionSampler){
SampleResult res = process_sampler(current, prev);// recursive call
threadContext.setCurrentSampler(prev);
current=null;
if (res!=null){
transactionSampler.addSubSamplerResult(res);
}
}
}
}
// Check if we have a sampler to sample
if(current != null) {
// Get the sampler ready to sample
SamplePackage pack = compiler.configureSampler(current);
// Hack: save the package for any transaction controllers
threadVars.putObject(PACKAGE_OBJECT, pack);
delay(pack.getTimers());
Sampler sampler = pack.getSampler();
sampler.setThreadContext(threadContext);
sampler.setThreadName(threadName);
TestBeanHelper.prepare(sampler);
// Perform the actual sample
SampleResult
result = sampler.sample(null);
// TODO: remove this useless Entry parameter
// If we got any results, then perform processing on the result
if (result != null) {
result.setGroupThreads(threadGroup.getNumberOfThreads());
result.setAllThreads(JMeterContextService.getNumberOfThreads());
result.setThreadName(threadName);
threadContext.setPreviousResult(result);
runPostProcessors(pack.getPostProcessors());
checkAssertions(pack.getAssertions(), result);
// Do not send subsamples to listeners which receive the transaction sample
List sampleListeners = getSampleListeners(pack, transactionPack, transactionSampler);
notifyListeners(sampleListeners, result);
compiler.done(pack);
// Add the result as subsample of transaction if we are in a transaction
if(transactionSampler != null) {
transactionSampler.addSubSamplerResult(result);
}
// Check if thread or test should be stopped
if (result.isStopThread() || (!result.isSuccessful() && onErrorStopThread)) {
stopThread();
}
if (result.isStopTest() || (!result.isSuccessful() && onErrorStopTest)) {
stopTest();
}
} else {
compiler.done(pack); // Finish up
}
}
if (scheduler) {
// checks the scheduler to stop the iteration
stopScheduler();
}
} catch (JMeterStopTestException e) {
log.info("Stopping Test: " + e.toString());
stopTest();
} catch (JMeterStopThreadException e) {
log.info("Stopping Thread: " + e.toString());
stopThread();
} catch (Exception e) {
if (current != null) {
log.error("Error while processing sampler '"+current.getName()+"' :", e);
} else {
log.error("", e);
}
}
return transactionResult;
}
/** /**
* Get the SampleListeners for the sampler. Listeners who receive transaction sample * Get the SampleListeners for the sampler. Listeners who receive transaction sample

View File

@ -63,6 +63,7 @@ but otherwise its behaviour is not consistent (or clearly specified).</p>
The menu item Options / Choose Language does not change all the displayed text to the new language. The menu item Options / Choose Language does not change all the displayed text to the new language.
To override the default local language, set the JMeter property "language" before starting JMeter. To override the default local language, set the JMeter property "language" before starting JMeter.
</p> </p>
<h3>Incompatible changes</h3> <h3>Incompatible changes</h3>
<ul> <ul>
The test element "Save Results to a file" is now shown as a Listener. The test element "Save Results to a file" is now shown as a Listener.
@ -77,7 +78,8 @@ It does not affect test plans or test behaviour.
<li>The "prev" and "sampler" objects are now defined for BSF test elements</li> <li>The "prev" and "sampler" objects are now defined for BSF test elements</li>
<li>Prompt to overwrite an existing file when first saving a new test plan</li> <li>Prompt to overwrite an existing file when first saving a new test plan</li>
<li>The test element "Save Results to a file" is now shown as a Listener</li> <li>The test element "Save Results to a file" is now shown as a Listener</li>
<li>Correct TestBeans to show the correct popup menu for Listeners</li> <li>Amend TestBeans to show the correct popup menu for Listeners</li>
<li>Fix NPE when using nested Transaction Controllers with parent samples</li>
</ul> </ul>
<h3>Improvements</h3> <h3>Improvements</h3>