Forum Discussion

Hoobajoob's avatar
Hoobajoob
Occasional Contributor
11 years ago

How to Sequence Runners and Generators

I have a SoapUI "setup" runner in a LoadUI scenario that loads some configuration settings and writes values out to properties for use by other SoapUI test cases.

I would like these runners to execute exactly once in the scenario, before any of the load generators start placing a load on the service-under-test, then kick off the load generators and have all of the runners that are driven by those generators use the property values generated by the "setup" runner

The sequence should go something like this:

1) execute the setup runner exactly once
2) after that runner is done, wait for some random interval of time
3) generate a burst of some random number of triggers
4) each trigger fires a sequence of SoapUI runners, and each of these runners uses the property values created by the one-time setup runner in step 1)
5) wait for some (different) random interval of time
6) go to step 3)
7) repeat until scenario time limits are reached

I have not been able to find a combination of Schedulers, Flows, and Generators that will implement this sequence.

Any suggestions?
  • Hoobajoob's avatar
    Hoobajoob
    Occasional Contributor
    So, if anybody else is interested, I solved this through a combination of SoapUI test case design changes and the creation of a new custom scheduler component. It's not an optimal solution, but it's good enough for my purposes.

    The test case design changes were to make 1 test case for each logical set of setup tasks, each of which sets property values that are to be used by all subsequent test cases. In my setup, I have 2 of these kinds of test cases - one that reads config from a database or file, and a second that does some one-time setup on a REST service in our testing infrastructure.

    For each of these test cases, I created an additional "one-shot wrapper" test case that consists of 4 steps:

    1) a "One-Shot Guard" groovy script step to ensure that the second step executes exactly once
    2) a "Run TestCase" step that uses a Run Mode setting of "Run primary TestCase (wait for running to finish)". This is the step that actually performs the desired setup operations.
    3) a step to transfer the return values from step 2) to the "one-shot wrapper" test case properties (could be a groovy script, or a property transfer step)
    4) an empty groovy script named "ExitTestCase"

    The "One-Shot Guard" step checks to see that at least one of the properties that is to be set by the setup operation is set to a value with a non-zero length, something like so:

    def testRunUrl = testRunner.testCase.getPropertyValue("test.run.url")
    if ( testRunUrl != null && testRunUrl.trim().length() > 0 ) {
    testRunner.gotoStepByName("ExitTestCase")
    }


    ...so, the first time through, the setup test case will not have executed, so that property will have an empty value. The if block will be false, and execution will proceed to step 2, the "Run TestCase" step.

    The "Run TestCase" step configuration is important, because it guarantees that even if the "One-Shot" SoapRunner in LoadUI is hooked up to a highly-concurrent generator, the first trigger to execute the actual setup test case (step 2 of the "one-shot wrapper" test case) will complete before any other trigger can complete. All subsequent triggers will blow past the "Run TestCase" step, so will use the property values set by that first trigger. All subsequent SoapRunners will get these initial property values.

    The Custom Component I derived from the "Interval" Scheduler component, adjusted so that it allows both a base duration and randomization factor for an "on time" and a "wait time". Once launched, it will:

    1) Generate a random number based on the "on time" randomization factor setting
    2) Add that random number to the base "on time" setting to generate an "on time" duration
    3) Send an "enabled" message to whatever component is plugged into the scheduler
    4) Wait for the "on time" duration to expire
    5) Generate a new random number based on the "wait time" randomization factor setting
    6) Add that random number to the base "wait time" setting to generate a "wait time" duration
    7) Send a "disabled" message to whatever component is plugged into the scheduler
    8) Wait for the "wait time" duration to expire
    9) go to step 1 and repeat until the scenario limits are reached or it's stopped


    So, my final configuration has the "RandomInterval" scheduler controlling a "Random" generator, and into the generator are plugged my 2 setup SoapRunners, and from there I have the rest of the behavior emulation plumbing.

    If anyone out there was able to get an equivalent functionality using the out-of-the-box LoadUI components, please share! I couldn't find a configuration that met my requirements.
  • Hoobajoob's avatar
    Hoobajoob
    Occasional Contributor
    One other thing to note - for the "One Shot Guard" groovy task, that conditional logic in the example I gave is subject to a race condition when the test case is driven by the LoadUI generators. 2 or more different threads can make it past the conditional logic before they block on the "Run TestCase" step, which will result in 2 or more threads running the setup task, which should be run no more than once.

    I think there are at least 3 possible solutions to that problem:

    1) Move the one-shot guard logic out of the "wrapper" test case and into the "wrapped" test case (the one that is executed by the Run TestCase step) - this would ensure that no 2 threads hit that conditional logic simultaneously
    2) Change the SoapUI Runner advanced settings in LoadUI so that it admits no more than 1 outstanding concurrent request on the setup test case
    3) Add yet another wrapper around the "One Shot" test case using a "Run TestCase" step with the same Run Mode settings

    ...I just changed the LoadUI advanced setting for max concurrent requests to "1".