Scripted Parameters

 

Scripted parameters are parameters whose values are generated by scripted code that you, the JTR user, have to write. Scripts can be written either using the BeanShell scripting language or the Groovy scripting language. It is also possible to plug-in your language of choice if needed.


Step 1: specify the scripting-engine factory

The very first step is about adding to the factories element a new factory sub-element right as follows:


<factory key="ITestScriptingEngine" fqn="jtr.script.impl.GroovyScriptEngine" />


Legal values for the fqn attribute are:

  1. -jtr.script.impl.BshScriptEngine

  2. -jtr.script.impl.GroovyScriptEngine


Step 2: use the param element with attribute type equal to scripted

Let’s suppose your runner Foo has a numeric property z that you want to be assigned to a value generated by a script that you have provided. That’s all you have to do:


<param name="z" type="scripted" value="bsh-1">

    <script-params>

        <script-param name="random" value="false"/>

        <script-param name="x" value="10" />

        <script-param name="y" value="12" />

    </script-params>

</param>


In the example above bsh-1 is the name of the script you have to write (in this example it is written in BeanShell). If the script we want to be invoked requires input parameters, we need to pass them using the script-params element followed by as many script-param sub-elements as we need.


Step 3: write your own scripts

Those scripts used to assign values to runners’ parameters are called parameterization-scripts. All those scripts have to be put in the jtr.xml file within the script element as follows:


<scripts>

    <p-scripts>

        <!-- ******************************************** -->               

        <!-- BeanShell version                            -->              

        <!-- ******************************************** -->

        <p-script name="bsh-1"

            body="id = jtrContext.getInstanceID();

                    if(random) {

                        res = bshMul(bshSum(x,y),Math.random());

                    } else {

                        res = bshSum(bshSum(x,y),id);

                    }">

            <inputs>

                <input name="random" type="boolean" />

                <input name="x" type="double"/>

                <input name="y" type="double"/>

            </inputs>

        </p-script>

        <!-- ******************************************** -->               

        <!-- Groovy version of the previous BSH example   -->              

        <!-- ******************************************** -->

        <p-script name="groovy-1"

            body='id = jtrContext.getInstanceID();

                    if(random) {

                        return (groovySum(x,y))*Math.random();

                    } else {

                        return x+y+id;

                    }'>

            <inputs>

                <input name="random" type="boolean" />

                <input name="x" type="double"/>

                <input name="y" type="double"/>

            </inputs>

    </p-script>

</scripts>


As you can see from the example above, we have two versions of the same script: the first one is written in BeanShell while the second one is written in Groovy. In both cases it is possible accessing the JTR-context to retrieve some useful information it is able to provide. Information provided is:

  1. -the current epoch

  2. -the current run

  3. -the category the script is running for

  4. -the instance ID of the runner the script is running for

  5. -the set of parameters the runner the script is running for has been assigned to

In the example above the instance-ID is used to generate a numeric value.


As you should have noticed, within the body of a p-script we can also invoke other scripts such as the groovySum script or the bshMul script. These are not scripts build in either JTR or the scripting language we are using, but library-scripts we can provide.


Step 4: write your own library-scripts if needed

Library-scripts are stored using the l-scripts element as follows:


<scripts>

    <l-scripts>

        <!-- Example of library script that declares typed parameters/variables

            and can use the same identifiers used elsewhere, even in the global scope -->

        <l-script body="bshSum(double x, double y) {

                        return x+y;

                        }"/>

        <!-- Example of library script that overrides another library-script

            and still uses typed parameters/variables -->

        <l-script body="bshSum(int x, int y) {

                        return x+y;

                        }"/>

        <!-- Example of library script that declares untyped parameters/variables

            and thus cannot use the same identifiers used elsewhere -->

        <l-script body="bshMul(_x,_y) {

                        return _x*_y;

                        }"/>

        <!-- This example shows how to access the JTR Script-Context from

            library scripts -->

        <l-script body="bshGetEpoch() {

                        return global.jtrContext.getCurrentEpoch();

                        }"/>

        <!-- A few Groovy examples -->

        <!-- l-script body="def groovySum(x,y) { x+y }"/>

        <l-script body="def groovyMul(x,y) { x*y }"/ -->

    </l-scripts>

    <p-scripts>

        <!-- ******************************************** -->               

        <!-- BeanShell p-scripts                          -->              

        <!-- ******************************************** -->

        <p-script name="bsh-1"

            body="id = global.jtrContext.getInstanceID();

                    if(random) {

                        res = bshMul(bshSum(x,y),Math.random());

                    } else {

                        res = bshSum(bshSum(x,y),id);

                    } return res;">

            <inputs>

                <input name="random" type="boolean" />

                <input name="x" type="double"/>

                <input name="y" type="double"/>

            </inputs>

        </p-script>

</scripts>


As you can see, all the library scripts invoked from parameterization-scripts are defined inside the l-scripts element using l-script elements. An l-script element only accepts a body attribute.


Obviously you can access every standard Java class from within your scripts, and also classes/interfaces of your own available in the runtime-classpath. The following example shows how to return from a BeanShell script an implementation of a user-defined interface:


<p-script name="bsh-2"

    body="import jtr.test.script.ScriptingTest.ScriptedRefIfc;

            ScriptedRefIfc res = new ScriptedRefIfc() {

                int sumInts(int x, int y) {

                    return bshSum(x,y);

                }

                int mulInts(int x, int y) {

                    return bshMul(x,y);

                }

                Date getCurrentDate() {

                    return today;

                }

                int getEpoch() {

                    return currentEpoch;

                }

                today = new Date();

                int currentEpoch = bshGetEpoch();

            };

            return res;"/>


In this awkward example we have decided to return from the script an implementation for the interface called ScriptedRefIfc.


Notes you need to know about

At the moment it is not possible mixing together library-scripts written with different languages.




Next step: writing a simple JSE JTR-Runner