View | Details | Raw Unified | Return to bug 59991
Collapse All | Expand All

(-)bin/jmeter.properties (+10 lines)
Lines 934-939 Link Here
934
# of Test and Thread Listeners.
934
# of Test and Thread Listeners.
935
935
936
#---------------------------------------------------------------------------
936
#---------------------------------------------------------------------------
937
# Groovy function
938
#---------------------------------------------------------------------------
939
940
#Path to Groovy file containing utility functions to make available to __g function
941
#groovy.utilities=
942
943
# Example 
944
#groovy.utilities=bin/utility.groovy
945
946
#---------------------------------------------------------------------------
937
# MailerModel configuration
947
# MailerModel configuration
938
#---------------------------------------------------------------------------
948
#---------------------------------------------------------------------------
939
949
(-)bin/utility.groovy (+2 lines)
Line 0 Link Here
1
// Uncomment this function and use it with ${__g(factorial(10))}
2
// def factorial(n) { n == 1 ? 1 : n * factorial(n - 1) }
(-)src/core/org/apache/jmeter/resources/messages.properties (+1 lines)
Lines 382-387 Link Here
382
graph_results_no_samples=No of Samples
382
graph_results_no_samples=No of Samples
383
graph_results_throughput=Throughput
383
graph_results_throughput=Throughput
384
graph_results_title=Graph Results
384
graph_results_title=Graph Results
385
groovy_function_expression=Expression to evaluate
385
grouping_add_separators=Add separators between groups
386
grouping_add_separators=Add separators between groups
386
grouping_in_controllers=Put each group in a new controller
387
grouping_in_controllers=Put each group in a new controller
387
grouping_in_transaction_controllers=Put each group in a new transaction controller
388
grouping_in_transaction_controllers=Put each group in a new transaction controller
(-)src/core/org/apache/jmeter/resources/messages_fr.properties (+1 lines)
Lines 375-380 Link Here
375
graph_results_no_samples=Nombre d'\u00E9chantillons
375
graph_results_no_samples=Nombre d'\u00E9chantillons
376
graph_results_throughput=D\u00E9bit
376
graph_results_throughput=D\u00E9bit
377
graph_results_title=Graphique de r\u00E9sultats
377
graph_results_title=Graphique de r\u00E9sultats
378
groovy_function_expression=Expression \u00E0 \u00E9valuer
378
grouping_add_separators=Ajouter des s\u00E9parateurs entre les groupes
379
grouping_add_separators=Ajouter des s\u00E9parateurs entre les groupes
379
grouping_in_controllers=Mettre chaque groupe dans un nouveau contr\u00F4leur
380
grouping_in_controllers=Mettre chaque groupe dans un nouveau contr\u00F4leur
380
grouping_in_transaction_controllers=Mettre chaque groupe dans un nouveau contr\u00F4leur de transaction
381
grouping_in_transaction_controllers=Mettre chaque groupe dans un nouveau contr\u00F4leur de transaction
(-)src/functions/org/apache/jmeter/functions/Groovy.java (+161 lines)
Line 0 Link Here
1
/**
2
 * 
3
 */
4
package org.apache.jmeter.functions;
5
6
import java.io.BufferedReader;
7
import java.io.File;
8
import java.io.FileReader;
9
import java.util.Collection;
10
import java.util.LinkedList;
11
import java.util.List;
12
import java.util.Properties;
13
14
import javax.script.Bindings;
15
import javax.script.ScriptEngine;
16
17
import org.apache.jmeter.engine.util.CompoundVariable;
18
import org.apache.jmeter.samplers.SampleResult;
19
import org.apache.jmeter.samplers.Sampler;
20
import org.apache.jmeter.threads.JMeterContext;
21
import org.apache.jmeter.threads.JMeterContextService;
22
import org.apache.jmeter.threads.JMeterVariables;
23
import org.apache.jmeter.util.JMeterUtils;
24
import org.apache.jmeter.util.JSR223TestElement;
25
import org.apache.jorphan.logging.LoggingManager;
26
import org.apache.log.Logger;
27
28
/**
29
 * __g function 
30
 * Provides a Groovy interpreter
31
 * @since 3.1
32
 */
33
public class Groovy extends AbstractFunction {
34
    private static final Logger log = LoggingManager.getLoggerForClass();
35
36
    private static final List<String> desc = new LinkedList<>();
37
38
    private static final String KEY = "__g"; //$NON-NLS-1$
39
40
    public static final String INIT_FILE = "groovy.utilities"; //$NON-NLS-1$
41
42
    static {
43
        desc.add(JMeterUtils.getResString("bsh_function_expression"));// $NON-NLS1$
44
        desc.add(JMeterUtils.getResString("function_name_paropt"));// $NON-NLS1$
45
    }
46
47
    private Object[] values;
48
    private ScriptEngine scriptEngine;
49
50
51
    public Groovy() {
52
    }
53
    
54
    /**
55
     * Populate variables to be passed to scripts
56
     * @param bindings Bindings
57
     */
58
    protected void populateBindings(Bindings bindings) {
59
    }
60
61
    /** {@inheritDoc} */
62
    @Override
63
    public synchronized String execute(SampleResult previousResult, Sampler currentSampler)
64
            throws InvalidVariableException {
65
        Bindings bindings = scriptEngine.createBindings();
66
        populateBindings(bindings);
67
68
69
        String script = ((CompoundVariable) values[0]).execute();
70
        String varName = ""; //$NON-NLS-1$
71
        if (values.length > 1) {
72
            varName = ((CompoundVariable) values[1]).execute().trim();
73
        }
74
75
        String resultStr = ""; //$NON-NLS-1$
76
        try {
77
78
            // Pass in some variables
79
            if (currentSampler != null) {
80
                bindings.put("sampler", currentSampler); // $NON-NLS-1$ 
81
            }
82
83
            if (previousResult != null) {
84
                bindings.put("prev", previousResult); //$NON-NLS-1$
85
            }
86
            bindings.put("log", log); // $NON-NLS-1$ (this name is fixed)
87
            // Add variables for access to context and variables
88
            bindings.put("threadName", Thread.currentThread().getName());
89
            JMeterContext jmctx = JMeterContextService.getContext();
90
            bindings.put("ctx", jmctx); // $NON-NLS-1$ (this name is fixed)
91
            JMeterVariables vars = jmctx.getVariables();
92
            bindings.put("vars", vars); // $NON-NLS-1$ (this name is fixed)
93
            Properties props = JMeterUtils.getJMeterProperties();
94
            bindings.put("props", props); // $NON-NLS-1$ (this name is fixed)
95
            // For use in debugging:
96
            bindings.put("OUT", System.out); // $NON-NLS-1$ (this name is fixed)
97
98
            
99
            // Execute the script
100
            Object out = scriptEngine.eval(script, bindings);
101
            if (out != null) {
102
                resultStr = out.toString();
103
            }
104
            
105
            if (varName.length() > 0) {// vars will be null on TestPlan
106
                if(vars != null) {
107
                    vars.put(varName, resultStr);
108
                }
109
            }
110
        } catch (Exception ex) // Mainly for bsh.EvalError
111
        {
112
            log.warn("Error running groovy script", ex);
113
        }
114
        if(log.isDebugEnabled()) {
115
            log.debug("__groovy("+script+","+varName+")=" + resultStr);
116
        }
117
        return resultStr;
118
119
    }
120
121
    /*
122
     * Helper method for use by scripts
123
     *
124
     */
125
    public void log_info(String s) {
126
        log.info(s);
127
    }
128
129
    /** {@inheritDoc} */
130
    @Override
131
    public void setParameters(Collection<CompoundVariable> parameters) throws InvalidVariableException {
132
        checkParameterCount(parameters, 1, 2);
133
        values = parameters.toArray();
134
        scriptEngine = JSR223TestElement.getInstance().getEngineByName("groovy");
135
        String fileName = JMeterUtils.getProperty(INIT_FILE);
136
        Bindings bindings = scriptEngine.createBindings();
137
        bindings.put("log", log);
138
        
139
        File file = new File(JMeterUtils.getJMeterHome(), fileName);
140
        if(file.exists() && file.canRead()) {
141
            try (FileReader fr = new FileReader(file); BufferedReader reader = new BufferedReader(fr)) {
142
                scriptEngine.eval(reader, bindings);
143
            } catch(Exception ex) {
144
                log.error("Failed loading script "+ file.getAbsolutePath(), ex);
145
            }
146
        }
147
    }
148
149
    /** {@inheritDoc} */
150
    @Override
151
    public String getReferenceKey() {
152
        return KEY;
153
    }
154
155
    /** {@inheritDoc} */
156
    @Override
157
    public List<String> getArgumentDesc() {
158
        return desc;
159
    }
160
161
}
(-)xdocs/usermanual/functions.xml (+47 lines)
Lines 125-130 Link Here
125
        <tr><td>Calculation</td><td> <a href="#__RandomFromMultipleVars">RandomFromMultipleVars</a></td><td>extracts an element from the values of a set of variables separated by <code>|</code></td><td>3.1</td></tr>
125
        <tr><td>Calculation</td><td> <a href="#__RandomFromMultipleVars">RandomFromMultipleVars</a></td><td>extracts an element from the values of a set of variables separated by <code>|</code></td><td>3.1</td></tr>
126
        <tr><td>Calculation</td><td> <a href="#__RandomString">RandomString</a></td><td>generate a random string</td><td>2.6</td></tr>
126
        <tr><td>Calculation</td><td> <a href="#__RandomString">RandomString</a></td><td>generate a random string</td><td>2.6</td></tr>
127
        <tr><td>Calculation</td><td> <a href="#__UUID">UUID</a></td><td>generate a random type 4 UUID</td><td>2.9</td></tr>
127
        <tr><td>Calculation</td><td> <a href="#__UUID">UUID</a></td><td>generate a random type 4 UUID</td><td>2.9</td></tr>
128
        <tr><td>Scripting</td><td> <a href="#__g">g</a></td><td>run a Groovy script</td><td>3.1</td></tr>
128
        <tr><td>Scripting</td><td> <a href="#__BeanShell">BeanShell</a></td><td>run a BeanShell script</td><td>1.X</td></tr>
129
        <tr><td>Scripting</td><td> <a href="#__BeanShell">BeanShell</a></td><td>run a BeanShell script</td><td>1.X</td></tr>
129
        <tr><td>Scripting</td><td> <a href="#__javaScript">javaScript</a></td><td>process JavaScript (Mozilla Rhino)</td><td>1.9</td></tr>
130
        <tr><td>Scripting</td><td> <a href="#__javaScript">javaScript</a></td><td>process JavaScript (Mozilla Rhino)</td><td>1.9</td></tr>
130
        <tr><td>Scripting</td><td> <a href="#__jexl">jexl</a></td><td>evaluate a Commons Jexl expression. This function is DEPRECATED as of JMeter 3.0, it will be removed in 3.1 version.</td><td>jexl1(1.1)</td></tr>
131
        <tr><td>Scripting</td><td> <a href="#__jexl">jexl</a></td><td>evaluate a Commons Jexl expression. This function is DEPRECATED as of JMeter 3.0, it will be removed in 3.1 version.</td><td>jexl1(1.1)</td></tr>
Lines 909-914 Link Here
909
</note>
910
</note>
910
</component>
911
</component>
911
912
913
<component index="&sect-num;.5.13" name="__g">
914
<description>
915
    <p>
916
    The g function evaluates <a href="http://groovy-lang.org/" >Apache Groovy</a> scripts passed to it, and returns the result.
917
</p>
918
<p>
919
If the property "<code>groovy.utilities</code>" is defined, it will be loaded by the ScriptEngine. 
920
This can be used to define common methods and variables. There is a
921
sample init file in the bin directory: <code>utility.groovy</code>.
922
</p>
923
<p>
924
The following variables are set before the script is executed:
925
<ul>
926
<li><code>log</code> - the logger for the BeanShell function (*)</li>
927
<li><code>ctx</code> - the current JMeter context variable</li>
928
<li><code>vars</code> - the current JMeter variables</li>
929
<li><code>props</code> - JMeter Properties object</li>
930
<li><code>threadName</code> - the threadName (String)</li>
931
<li><code>sampler</code> - the current Sampler, if any</li>
932
<li><code>prev</code> - the previous SampleResult, if any</li>
933
<li><code>OUT</code> - System.out</li>
934
</ul>
935
(*) means that this is set before the init file, if any, is processed. 
936
Other variables vary from invocation to invocation.
937
</p>
938
</description>
939
940
<properties>
941
        <property name="Expression to evaluate" required="Yes">A groovy script (not a file name)</property>
942
        <property name="Name of variable" required="No">A reference name for reusing the value
943
               computed by this function.</property>
944
        
945
</properties>
946
<p>
947
Example:
948
<dl>
949
<dt><code>${__g(123*456)}</code></dt><dd>returns <code>56088</code></dd>
950
<dt><code>${__g("${var}".substring(0\,2))}</code></dt><dd>If var's value is <code>JMeter</code>, it will return <code>JM</code> as it runs <code>String.substring(0,2)</code> </dd>
951
</dl>
952
</p>
953
<note>
954
Remember to include any necessary quotes for text strings and JMeter variables that represent text strings.
955
</note>
956
</component>
957
958
912
<component index="&sect-num;.5.14" name="__split">
959
<component index="&sect-num;.5.14" name="__split">
913
<description>
960
<description>
914
    <p>
961
    <p>

Return to bug 59991