Ok, so here's the thing. If you have a controller that does nothing but return null,
a loop
controller is going to continue searching for a sub-controller with a sampler to
return. If you're
controller returned a sampler, then null, then a sampler, then null, etc (like a
normal controller
does), then this problem doesn't show up. It's when you have a sampler that insists
on never
providing a sampler, yet also insists it's got samplers to provide (ie, it's not
"done").
So, here you are trying to make a triggered controller that could reasonably have no
samplers
to provide, but insists that it might at some point in the future. It's sort of a new
situation not
anticipated by the current code. You could create a NullSampler that returns a dummy
ResponseData object to get around this, though that's a substandard solution since
your
listeners will get a lot of these things. But, I'm not sure I see a better solution
until JMeter
learns about this new possibility.
-Mike
On 24 Jan 2004 at 16:00, Jerry Pulley wrote:
> I recently encountered some problems with the design of a controller,
> and discussed them with M. Stover in the "TriggeredController design"
> thread on jmeter-user. Here's what Mike said about
> GenericController.next():
>
> > The semantics of the "next()" method are supposed to be like so:
> >
> > returns Sampler - sampler is intended to be executed.
> >
> > returns null, isDone() = false: This should indicate the controller
> > has finished a full round of iteration, and the test should move on to
> > the next controller. If the test runs another iteration, the
> > controller should be ready for everything to begin again. This is why
> > the "nextIsNull()" method calls reinitialize().
> >
> > returns null, isDone() = true; The controller has finished entirely,
> > and should not be run again. Indeed, it is generally dropped from the
> > test entirely.
>
> The current version of JMeter fails to behave in the manner described in
> the second case. If a subclass of GenericController is an immediate
> child of a LoopController (e.g. the one in the ThreadGroup) and its
> next() method returns null without setting "done", an infinite chain of
> recursive calls results. The attached test case demonstrates the
> problem.
>
> It's interesting that the "loops" property of some LoopController in the
> tree needs to be set to -1 for this problem to surface. (That's what
> ThreadGroupGui does when creating the loop controller for a thread
> group.) What's even more interesting is that if the test tree contains
> an explicit loop controller with "loops" set to a positive value, and
> that loop controller contains the controller that returns null, then it
> still fails. These observations might be of interest to someone who
> knows JMeter internals. In the absence of any Javadoc I can't really
> determine a firm definition of the "loops" property, so I'm leaving this
> to the experts.
>
> jp
>
> package net.jpulley.jmeter19.controller;
>
> import junit.framework.Test;
> import junit.framework.TestCase;
> import junit.framework.TestSuite;
> import org.apache.jmeter.control.GenericController;
> import org.apache.jmeter.control.LoopController;
> import org.apache.jmeter.samplers.Sampler;
> import org.apache.jmeter.threads.ThreadGroup;
> import org.apache.log.Hierarchy;
> import org.apache.log.Priority;
>
> public class LoopControllerTest2 extends TestCase {
> public LoopControllerTest2(String name) {
> super(name);
> }
>
> public static Test suite() {
> return new TestSuite(LoopControllerTest2.class);
> }
>
> public static void main(String[] args) {
> junit.textui.TestRunner.run(suite());
> }
>
> protected void setUp() {
> Hierarchy.getDefaultHierarchy()
> .setDefaultPriority(Priority.NONE);
> }
>
> public void testInThreadGroup() throws Exception {
> //set up a ThreadGroup like ThreadGroupGui does
> ThreadGroup threadGroup = new ThreadGroup();
> LoopController threadGroupLoopCtlr = new LoopController();
> threadGroupLoopCtlr.setLoops(-1);
> threadGroup.setSamplerController(threadGroupLoopCtlr);
>
> NullController nullCtlr = new NullController(false, 0);
> threadGroup.addTestElement(nullCtlr);
>
> //test
> try {
> Sampler smplr = threadGroup.next();
> } catch (java.lang.StackOverflowError err) {
> fail("Stack overflow");
> }
> }
>
> public void testAsSubcontroller() throws Exception {
> //set up a ThreadGroup like ThreadGroupGui does
> ThreadGroup threadGroup = new ThreadGroup();
> LoopController threadGroupLoopCtlr = new LoopController();
> threadGroupLoopCtlr.setLoops(-1);
> threadGroup.setSamplerController(threadGroupLoopCtlr);
>
> //add a loop controller to the thread group
> LoopController loopCtlr = new LoopController();
> loopCtlr.setLoops(10);
> threadGroup.addTestElement(loopCtlr);
>
> //add a test controller to the loop controller
> NullController nullCtlr = new NullController(false, 0);
> loopCtlr.addTestElement(nullCtlr);
>
> //test
> try {
> Sampler smplr = threadGroup.next();
> } catch (java.lang.StackOverflowError err) {
> fail("Stack overflow");
> }
> }
>
> public void testStandaloneFinite() throws Exception {
> LoopController loopCtlr = new LoopController();
> loopCtlr.setLoops(10);
>
> NullController nullCtlr = new NullController(false, 0);
> loopCtlr.addTestElement(nullCtlr);
>
> //test
> try {
> Sampler smplr = loopCtlr.next();
> } catch (java.lang.StackOverflowError err) {
> fail("Stack overflow");
> }
> }
>
> public void testStandaloneInfinite() throws Exception {
> LoopController loopCtlr = new LoopController();
> loopCtlr.setLoops(-1);
>
> NullController nullCtlr = new NullController(false, 0);
> loopCtlr.addTestElement(nullCtlr);
>
> //test
> try {
> Sampler smplr = loopCtlr.next();
> } catch (java.lang.StackOverflowError err) {
> fail("Stack overflow");
> }
> }
>
> //A simple controller that's never done and always
> //returns null. Create it with (true, n) to get a
> //stack dump at the nth call.
> public static class NullController extends GenericController {
> private int callCount;
> private boolean dumpStack;
> private int whichIter;
>
> public NullController(boolean dumpStack, int whichIter) {
> super();
> this.dumpStack = dumpStack;
> this.whichIter = whichIter;
> }
>
> public NullController() {
> this(true, 5);
> }
>
> public Sampler next() {
> if (dumpStack && ++callCount == whichIter) {
> Thread.dumpStack();
> }
> return null;
> }
> }
> }
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [EMAIL PROTECTED]
> For additional commands, e-mail: [EMAIL PROTECTED]
>
--
Michael Stover
[EMAIL PROTECTED]
Yahoo IM: mstover_ya
ICQ: 152975688
AIM: mstover777
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]