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]