mstover1 2002/07/12 20:17:49
Modified: docs running.html
docs/usermanual glossary.html index.html
src_1/org/apache/jmeter/protocol/all/modifier
CompoundFunction.java Function.java
RegexFunction.java
src_1/org/apache/jmeter/threads TestCompiler.java
xdocs/usermanual glossary.xml index.xml
Added: docs/usermanual functions.html
src_1/org/apache/jmeter/protocol/all/modifier
AbstractFunction.java
xdocs/usermanual functions.xml
Log:
New Function implementations plus a quick draft of documentation for functions
Revision Changes Path
1.46 +0 -0 jakarta-jmeter/docs/running.html
Index: running.html
===================================================================
RCS file: /home/cvs/jakarta-jmeter/docs/running.html,v
retrieving revision 1.45
retrieving revision 1.46
diff -u -r1.45 -r1.46
1.11 +1 -1 jakarta-jmeter/docs/usermanual/glossary.html
Index: glossary.html
===================================================================
RCS file: /home/cvs/jakarta-jmeter/docs/usermanual/glossary.html,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -r1.10 -r1.11
--- glossary.html 7 Mar 2002 23:03:12 -0000 1.10
+++ glossary.html 13 Jul 2002 03:17:48 -0000 1.11
@@ -68,7 +68,7 @@
<table border="0" cellspacing="0" cellpadding="2" width="100%">
<tr><td bgcolor="#525D76">
<font color="#ffffff" face="arial,helvetica,sanserif">
- <a name="glossary"><strong>14. Glossary</strong></a>
+ <a name="glossary"><strong>15. Glossary</strong></a>
</font>
</td></tr>
<tr><td>
1.24 +8 -1 jakarta-jmeter/docs/usermanual/index.html
Index: index.html
===================================================================
RCS file: /home/cvs/jakarta-jmeter/docs/usermanual/index.html,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -r1.23 -r1.24
--- index.html 26 Jun 2002 00:59:49 -0000 1.23
+++ index.html 13 Jul 2002 03:17:48 -0000 1.24
@@ -645,8 +645,15 @@
<li >
+
<a href="functions.html">
+ 14. Functions
+ </a>
+ </li>
+
+
+
<li >
<a href="glossary.html">
- 14. Glossary
+ 15. Glossary
</a>
</li>
1.1 jakarta-jmeter/docs/usermanual/functions.html
Index: functions.html
===================================================================
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<!-- Content Stylesheet for Site -->
<!-- start the processing -->
<!-- ======================================================================
-->
<!-- Main Page Section -->
<!-- ======================================================================
-->
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;
charset=iso-8859-1"/>
<title>JMeter - User's Manual: Introduction</title>
</head>
<body bgcolor="#ffffff" text="#000000" link="#525D76">
<table border="0" cellspacing="0">
<!-- TOP IMAGE -->
<tr>
<td colspan="2">
<a href="http://jakarta.apache.org"><img
src="http://jakarta.apache.org/images/jakarta-logo.gif" align="left" border="0"/></a>
</td>
</tr>
</table>
<table border="0" width="100%" cellspacing="4">
<tr><td colspan="2">
<hr noshade="" size="1"/>
</td></tr>
<tr>
<!-- LEFT SIDE NAVIGATION -->
<td width="20%" valign="top"
nowrap="true">
<p><strong>About</strong></p>
<ul>
<li> <a
href="../index.html">Overview</a>
</li>
<li> <a
href="http://jakarta.apache.org/builds/jakarta-jmeter/">Download</a>
</li>
<li> <a
href="../changes.html">Changes</a>
</li>
<li> <a
href="http://nagoya.apache.org/bugzilla/buglist.cgi?bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&email1=&emailtype1=substring&emailassigned_to1=1&email2=&emailtype2=substring&emailreporter2=1&bugidtype=include&bug_id=&changedin=&votes=&chfieldfrom=&chfieldto=Now&chfieldvalue=&product=JMeter&short_desc=&short_desc_type=substring&long_desc=&long_desc_type=substring&bug_file_loc=&bug_file_loc_type=substring&keywords=&keywords_type=anywords&field0-0-0=noop&type0-0-0=noop&value0-0-0=&cmdtype=doit&order=Reuse+same+sort+as+last+time">Known
Bugs</a>
</li>
<li> <a
href="../license.html">License</a>
</li>
<li> <a
href="../todo.html">TODO</a>
</li>
</ul>
<p><strong>Documentation</strong></p>
<ul>
<li> <a
href="../usermanual/index.html">User Manual</a>
</li>
<li> <a
href="../extending/index.html">Developer Manual</a>
</li>
</ul>
<p><strong>Community</strong></p>
<ul>
<li> <a
href="http://jakarta.apache.org/site/getinvolved.html">Get Involved</a>
</li>
<li> <a
href="http://jakarta.apache.org/site/mail.html">Mailing Lists</a>
</li>
<li> <a
href="http://jakarta.apache.org/site/cvsindex.html">CVS Repositories</a>
</li>
</ul>
</td>
<td width="80%" align="left"
valign="top">
<table border="0" cellspacing="0" cellpadding="2" width="100%">
<tr><td bgcolor="#525D76">
<font color="#ffffff" face="arial,helvetica,sanserif">
<a name="functions"><strong>14. Functions</strong></a>
</font>
</td></tr>
<tr><td>
<blockquote>
<p >
JMeter functions are special values that can populate fields of any Sampler or other
configuration
element in a test tree. A function looks like this:
</p>
<p >
<code >
${__functionName(var1,var2,var3)}
</code>
</p>
<p >
Where "__functionName"
matches the name of an existing built-in or user-defined function.
<br >
</br>
Parentheses surround the parameters sent to the function. The actual parameters
vary from function
to function. Functions that require no parameters can leave off the parentheses.
The function itself
is wrapped in ${}.
</p>
<table
border="0" cellspacing="0" cellpadding="2" width="100%">
<tr><td bgcolor="#828DA6">
<font color="#ffffff" face="arial,helvetica,sanserif">
<a name="what_can_do"><strong>14.1 What can functions
do</strong></a>
</font>
</td></tr>
<tr><td>
<blockquote>
<p >
There are two kinds of
functions: user-defined static values, and built-in functions.
<br >
</br>
User-defined static values allows the user to define variables to be replaced with
their static value when
a test tree is compiled and submitted to be run. This replacement happens once at
the beginning of the test
run. This could be used to replace the DOMAIN field of all HTTP requests, for
example - making it a simple
matter to change a test to target a different server with the same test.
</p>
<p >
This type of
replacement is possible without functions, but was less convenient and less intuitive.
It required users to create default config elements that would fill in blank values
of Samplers. User-defined
functions allows one to replace only part of any given value, not just filling in
blank values.
</p>
<p >
With built-in functions users can compute new values at run-time based on previous
response data, which
thread the function is in, the time, and many other sources. These values are
generated fresh for every
request throughout the course of the test.
</p>
</blockquote>
</td></tr>
<tr><td><br/></td></tr>
</table>
<table
border="0" cellspacing="0" cellpadding="2" width="100%">
<tr><td bgcolor="#828DA6">
<font color="#ffffff" face="arial,helvetica,sanserif">
<a name="where"><strong>14.2 Where can functions be
used?</strong></a>
</font>
</td></tr>
<tr><td>
<blockquote>
<p >
A user-defined
function can be written into any field of any test component. Some fields do not
allow random strings
because they are expecting numbers, and thus will not accept a function. However,
most fields will allow
functions.
</p>
<p >
Built-in functions can
be written into any field of non-controller test components. This includes
Samplers, Timers, Listeners, Modifiers, Assertions, and Config Elements.
</p>
</blockquote>
</td></tr>
<tr><td><br/></td></tr>
</table>
<table
border="0" cellspacing="0" cellpadding="2" width="100%">
<tr><td bgcolor="#828DA6">
<font color="#ffffff" face="arial,helvetica,sanserif">
<a name="how"><strong>14.3 Writing the function
string</strong></a>
</font>
</td></tr>
<tr><td>
<blockquote>
<p >
User-defined functions
take the form:
<code >
${varName}
</code>
. In the
TestPlan tree element, a two-column table
of user-defined values is kept, matching up variable names with static values.
Referencing the
variable in a test element is done by bracketing the variable name with '${' and '}'.
</p>
<p >
Built-in functions are
written in the same manner, but by convention, the names of built-in
parameters begin with "__" to avoid conflict with user value names
<sup >
*
</sup>
. Some
functions take arguments to
configure them, and these go in parentheses, comma-delimited. If the function takes
no arguments, the parentheses can
be left out. A further complication for argument values that themselves contain
commas is that the value
should be encoded the way HTTP parameters are encoded. JMeter provides a tool to
help you construct
function calls for various built-in functions, which you can then copy-paste. If
your argument values
do not contain commas, encoding is not required.
</p>
<p><table
border="1" bgcolor="#bbbb00" width="50%" cellspacing="0" cellpadding="2">
<tr><td>
<sup >
*
</sup>
If you define
a user-defined static variable with the same name as a built-in function, your static
variable will override the built-in function.
</td></tr>
</table></p>
</blockquote>
</td></tr>
<tr><td><br/></td></tr>
</table>
</blockquote>
</p>
</td></tr>
<tr><td><br/></td></tr>
</table>
</td>
</tr>
<!-- FOOTER -->
<tr><td colspan="2">
<hr noshade="" size="1"/>
</td></tr>
<tr><td colspan="2">
<div align="center"><font
color="#525D76" size="-1"><em>
Copyright © 1999-2001, Apache
Software Foundation
</em></font></div>
</td></tr>
</table>
</body>
</html>
<!-- end the processing -->
1.2 +32 -5
jakarta-jmeter/src_1/org/apache/jmeter/protocol/all/modifier/CompoundFunction.java
Index: CompoundFunction.java
===================================================================
RCS file:
/home/cvs/jakarta-jmeter/src_1/org/apache/jmeter/protocol/all/modifier/CompoundFunction.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- CompoundFunction.java 12 Jul 2002 02:00:46 -0000 1.1
+++ CompoundFunction.java 13 Jul 2002 03:17:48 -0000 1.2
@@ -1,5 +1,6 @@
package org.apache.jmeter.protocol.all.modifier;
+import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
@@ -11,11 +12,8 @@
import org.apache.jmeter.samplers.Sampler;
import org.apache.jmeter.util.ClassFinder;
import org.apache.oro.text.perl.Perl5Util;
-import org.apache.oro.text.regex.Pattern;
import org.apache.oro.text.regex.PatternCompiler;
-import org.apache.oro.text.regex.PatternMatcher;
import org.apache.oro.text.regex.Perl5Compiler;
-import org.apache.oro.text.regex.Perl5Matcher;
/**
* @author mstover
@@ -66,7 +64,28 @@
* @see Function#execute(SampleResult)
*/
public String execute(SampleResult previousResult,Sampler currentSampler) {
- return null;
+ if(compiledComponents == null || compiledComponents.size() == 0)
+ {
+ return "";
+ }
+ StringBuffer results = new StringBuffer();
+ Iterator iter = compiledComponents.iterator();
+ while(iter.hasNext())
+ {
+ Object item = iter.next();
+ if(item instanceof Function)
+ {
+ try {
+
results.append(((Function)item).execute(previousResult,currentSampler));
+ } catch(InvalidVariableException e) {
+ }
+ }
+ else
+ {
+ results.append(item);
+ }
+ }
+ return results.toString();
}
public CompoundFunction getFunction()
@@ -249,17 +268,20 @@
assertTrue(function.hasFunction());
assertTrue(!function.hasStatics());
assertEquals("hello
world",((Function)function.compiledComponents.getFirst()).execute(result,null));
+ assertEquals("hello world",function.execute(result,null));
}
public void testParseExample2() throws Exception
{
- function.setParameters("It should
say:${${__regexFunction(<html>(.*)</html>,$1$)}}");
+ function.setParameters("It should
say:${${__regexFunction("+URLEncoder.encode("<html>(.*)</html>")+",$1$)}}");
assertEquals(3,function.compiledComponents.size());
assertEquals("It should
say:${",function.compiledComponents.getFirst().toString());
assertTrue(function.hasFunction());
assertTrue(!function.hasStatics());
assertEquals("hello
world",((Function)function.compiledComponents.get(1)).execute(result,null));
assertEquals("}",function.compiledComponents.get(2).toString());
+ assertEquals("It should say:${hello
world}",function.execute(result,null));
+ assertEquals("It should
say:${<html>(.*)</html>,$1$}",function.execute(null,null));
}
public void testParseExample3() throws Exception
@@ -270,6 +292,9 @@
assertTrue(!function.hasStatics());
assertEquals("hello
world",((Function)function.compiledComponents.get(0)).execute(result,null));
assertEquals("hellorld",((Function)function.compiledComponents.get(1)).execute(result,null));
+ assertEquals("hello
worldhellorld",function.execute(result,null));
+
assertEquals("<html>(.*)</html>,$1$<html>(.*o)(.*o)(.*)</html>,$1$$3$",
+ function.execute(null,null));
}
public void testParseExample4() throws Exception
@@ -280,6 +305,8 @@
assertTrue(!function.hasStatics());
assertEquals("${non-existing function}",
function.compiledComponents.getFirst().toString());
+ assertEquals("${non-existing
function}",function.execute(result,null));
+ assertEquals("${non-existing
function}",function.execute(null,null));
}
public void testParseExample5() throws Exception
1.2 +2 -1
jakarta-jmeter/src_1/org/apache/jmeter/protocol/all/modifier/Function.java
Index: Function.java
===================================================================
RCS file:
/home/cvs/jakarta-jmeter/src_1/org/apache/jmeter/protocol/all/modifier/Function.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- Function.java 12 Jul 2002 02:00:46 -0000 1.1
+++ Function.java 13 Jul 2002 03:17:48 -0000 1.2
@@ -11,7 +11,8 @@
*/
public interface Function {
- public String execute(SampleResult previousResult,Sampler currentSampler);
+ public String execute(SampleResult previousResult,Sampler currentSampler)
+ throws InvalidVariableException;
public void setParameters(String parameters) throws InvalidVariableException;
1.2 +26 -38
jakarta-jmeter/src_1/org/apache/jmeter/protocol/all/modifier/RegexFunction.java
Index: RegexFunction.java
===================================================================
RCS file:
/home/cvs/jakarta-jmeter/src_1/org/apache/jmeter/protocol/all/modifier/RegexFunction.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- RegexFunction.java 12 Jul 2002 02:00:46 -0000 1.1
+++ RegexFunction.java 13 Jul 2002 03:17:48 -0000 1.2
@@ -3,6 +3,7 @@
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
@@ -28,13 +29,13 @@
* To change this generated comment edit the template variable "typecomment":
* Window>Preferences>Java>Templates.
*/
-public class RegexFunction implements Function {
+public class RegexFunction extends AbstractFunction {
public static final String ALL = "ALL";
public static final String RAND = "RAND";
public static final String KEY = "__regexFunction";
- Random rand = new Random();
+ private static Random rand = new Random();
Pattern searchPattern;
Object[] template;
String valueIndex,defaultValue,between;
@@ -56,6 +57,10 @@
*/
public String execute(SampleResult previousResult,Sampler currentSampler)
{
+ if(previousResult == null || previousResult.getResponseData() == null)
+ {
+ return defaultValue;
+ }
List collectAllMatches = new ArrayList();
try {
PatternMatcher matcher = new Perl5Matcher();
@@ -131,52 +136,35 @@
public void setParameters(String params) throws InvalidVariableException
{
- StringTokenizer tk = new StringTokenizer(params,",",true);
- valueIndex = "1";
- between = "";
- defaultValue = "";
- String temp = null;
- try {
- searchPattern =
compiler.compile(URLDecoder.decode(tk.nextToken()));
- } catch(MalformedPatternException e) {
- throw new InvalidVariableException(e.getMessage());
- }
- tk.nextToken();
- generateTemplate(URLDecoder.decode(tk.nextToken()));
- if(tk.hasMoreTokens())
+ try
{
- tk.nextToken();
- temp = tk.nextToken();
- if(!temp.equals(","))
+ Iterator tk = parseArguments(params).iterator();
+ valueIndex = "1";
+ between = "";
+ defaultValue = URLDecoder.decode(params);
+ searchPattern = compiler.compile((String)tk.next());
+ generateTemplate((String)tk.next());
+ if(tk.hasNext())
{
- valueIndex = temp;
+ valueIndex = (String)tk.next();
}
- }
- if(tk.hasMoreTokens())
- {
- if(!temp.equals(","))
+ if(tk.hasNext())
{
- tk.nextToken();
+ between = (String)tk.next();
}
- temp = tk.nextToken();
- if(!temp.equals(","))
+ if(tk.hasNext())
{
- between = URLDecoder.decode(temp);
+ defaultValue = (String)tk.next();
}
+ } catch(MalformedPatternException e) {
+ e.printStackTrace();
+ throw new InvalidVariableException("Bad regex
pattern");
}
- if(tk.hasMoreTokens())
+ catch(Exception e)
{
- if(!temp.equals(","))
- {
- tk.nextToken();
- }
- temp = tk.nextToken();
- if(!temp.equals(","))
- {
- defaultValue = URLDecoder.decode(temp);
- }
+ throw new InvalidVariableException(e.getMessage());
}
- }
+ }
private void generateTemplate(String rawTemplate)
{
1.1
jakarta-jmeter/src_1/org/apache/jmeter/protocol/all/modifier/AbstractFunction.java
Index: AbstractFunction.java
===================================================================
package org.apache.jmeter.protocol.all.modifier;
import java.net.URLDecoder;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.StringTokenizer;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.samplers.Sampler;
/**
* @author mstover
*
* To change this generated comment edit the template variable "typecomment":
* Window>Preferences>Java>Templates.
*/
public abstract class AbstractFunction implements Function {
/**
* @see Function#execute(SampleResult, Sampler)
*/
abstract public String execute(SampleResult previousResult, Sampler
currentSampler)
throws InvalidVariableException;
/**
* @see Function#setParameters(String)
*/
abstract public void setParameters(String parameters) throws
InvalidVariableException;
/**
* @see Function#getReferenceKey()
*/
abstract public String getReferenceKey();
/**
* Provides a convenient way to parse the given argument string into a
collection of
* individual arguments. Takes care of splitting the string based on commas,
generates
* blank strings for values between adjacent commas, and decodes the string
using URLDecoder.
*/
protected Collection parseArguments(String params)
{
StringTokenizer tk = new StringTokenizer(params,",",true);
List arguments = new LinkedList();
String previous = "";
while(tk.hasMoreTokens())
{
String arg = tk.nextToken();
if(arg.equals(",") && previous.equals(","))
{
arguments.add("");
}
else if(!arg.equals(","))
{
arguments.add(URLDecoder.decode(arg));
}
previous = arg;
}
return arguments;
}
}
1.6 +165 -9 jakarta-jmeter/src_1/org/apache/jmeter/threads/TestCompiler.java
Index: TestCompiler.java
===================================================================
RCS file:
/home/cvs/jakarta-jmeter/src_1/org/apache/jmeter/threads/TestCompiler.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- TestCompiler.java 21 May 2002 03:36:44 -0000 1.5
+++ TestCompiler.java 13 Jul 2002 03:17:48 -0000 1.6
@@ -1,12 +1,21 @@
package org.apache.jmeter.threads;
-import java.util.*;
-import org.apache.jmeter.config.Arguments;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
import org.apache.jmeter.assertions.Assertion;
-import org.apache.jmeter.timers.Timer;
+import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.config.ConfigTestElement;
import org.apache.jmeter.config.Modifier;
import org.apache.jmeter.config.ResponseBasedModifier;
import org.apache.jmeter.control.GenericController;
+import org.apache.jmeter.protocol.all.modifier.Function;
+import org.apache.jmeter.protocol.all.modifier.InvalidVariableException;
import org.apache.jmeter.protocol.http.sampler.HTTPSampler;
import org.apache.jmeter.samplers.SampleEvent;
import org.apache.jmeter.samplers.SampleListener;
@@ -14,6 +23,7 @@
import org.apache.jmeter.samplers.Sampler;
import org.apache.jmeter.testelement.PerSampleClonable;
import org.apache.jmeter.testelement.TestElement;
+import org.apache.jmeter.timers.Timer;
import org.apache.jmeter.util.ListedHashTree;
import org.apache.jmeter.util.ListedHashTreeVisitor;
@@ -37,8 +47,10 @@
{
LinkedList stack = new LinkedList();
Map samplerConfigs = new HashMap();
+ Set objectsWithFunctions = new HashSet();
ListedHashTree testTree;
SampleResult previousResult;
+ Sampler currentSampler;
private static Set pairing = new HashSet();
/****************************************
@@ -91,12 +103,17 @@
***************************************/
public SamplePackage configureSampler(Sampler sampler)
{
+ currentSampler = sampler;
SamplePackage ret = new SamplePackage();
Sampler clonedSampler = sampler;
if(sampler instanceof PerSampleClonable)
{
clonedSampler = (Sampler)((PerSampleClonable)sampler).clone();
}
+ if(objectsWithFunctions.contains(sampler))
+ {
+ replaceValues(clonedSampler);
+ }
ret.setSampler(clonedSampler);
ret.addSampleListener(this);
Iterator iter = ((List)samplerConfigs.get(sampler)).iterator();
@@ -154,9 +171,18 @@
Iterator iter = testTree.list(stack.subList(0, i)).iterator();
while(iter.hasNext())
{
- configs.add(iter.next());
+ TestElement item = (TestElement)iter.next();
+ if(hasFunctions(item))
+ {
+ objectsWithFunctions.add(item);
+ }
+ configs.add(item);
}
}
+ if(hasFunctions(sam))
+ {
+ objectsWithFunctions.add(sam);
+ }
samplerConfigs.put(sam, configs);
}
@@ -259,6 +285,7 @@
private void layerElement(SamplePackage ret,TestElement config, Sampler
clonedSampler)
{
+ boolean replace = objectsWithFunctions.contains(config);
if(config instanceof PerSampleClonable)
{
config = (TestElement)((PerSampleClonable)config).clone();
@@ -283,6 +310,135 @@
{
ret.addTimer((Timer)config);
}
+ if(replace && config instanceof PerSampleClonable)
+ {
+ replaceValues(config);
+ }
+ else if(replace)
+ {
+ config = (TestElement)config.clone();
+ replaceValues(config);
+ }
clonedSampler.addTestElement(config);
}
+
+ private boolean hasFunctions(TestElement el)
+ {
+ Iterator iter = el.getPropertyNames().iterator();
+ while(iter.hasNext())
+ {
+ String propName = (String)iter.next();
+ Object propValue = el.getProperty(propName);
+ if(propValue instanceof Function)
+ {
+ return true;
+ }
+ else if(propValue instanceof TestElement)
+ {
+ if(hasFunctions((TestElement)propValue))
+ {
+ return true;
+ }
+ }
+ else if(propValue instanceof Collection)
+ {
+ if(hasFunctions((Collection)propValue))
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private boolean hasFunctions(Collection values)
+ {
+ Iterator iter = values.iterator();
+ while(iter.hasNext())
+ {
+ Object val = iter.next();
+ if(val instanceof TestElement)
+ {
+ if(hasFunctions((TestElement)val))
+ {
+ return true;
+ }
+ }
+ else if(val instanceof Function)
+ {
+ return true;
+ }
+ else if(val instanceof Collection)
+ {
+ if(hasFunctions((Collection)val))
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ private void replaceValues(TestElement el)
+ {
+ Iterator iter = el.getPropertyNames().iterator();
+ while(iter.hasNext())
+ {
+ String propName = (String)iter.next();
+ Object propValue = el.getProperty(propName);
+ if(propValue instanceof Function)
+ {
+ try
+ {
+
el.setProperty(propName,((Function)propValue).execute(previousResult,currentSampler));
+ }
+ catch(InvalidVariableException e)
+ {}
+ }
+ else if(propValue instanceof TestElement)
+ {
+ replaceValues((TestElement)propValue);
+ }
+ else if(propValue instanceof Collection)
+ {
+
el.setProperty(propName,replaceValues((Collection)propValue));
+ }
+ }
+ }
+
+ private Collection replaceValues(Collection values)
+ {
+ Collection newColl = null;
+ try {
+ newColl = (Collection)values.getClass().newInstance();
+ } catch(Exception e) {
+ e.printStackTrace();
+ return values;
+ }
+ Iterator iter = values.iterator();
+ while(iter.hasNext())
+ {
+ Object val = iter.next();
+ if(val instanceof TestElement)
+ {
+ replaceValues((TestElement)val);
+ }
+ else if(val instanceof Function)
+ {
+ try
+ {
+ val =
((Function)val).execute(previousResult,currentSampler);
+ }
+ catch(InvalidVariableException e)
+ {}
+ }
+ else if(val instanceof Collection)
+ {
+ val = replaceValues((Collection)val);
+ }
+ newColl.add(val);
+ }
+ return newColl;
+ }
+
}
1.4 +1 -1 jakarta-jmeter/xdocs/usermanual/glossary.xml
Index: glossary.xml
===================================================================
RCS file: /home/cvs/jakarta-jmeter/xdocs/usermanual/glossary.xml,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- glossary.xml 24 Feb 2002 18:17:18 -0000 1.3
+++ glossary.xml 13 Jul 2002 03:17:49 -0000 1.4
@@ -7,7 +7,7 @@
<body>
-<section name="14. Glossary" anchor="glossary">
+<section name="15. Glossary" anchor="glossary">
</section>
</body>
1.23 +2 -1 jakarta-jmeter/xdocs/usermanual/index.xml
Index: index.xml
===================================================================
RCS file: /home/cvs/jakarta-jmeter/xdocs/usermanual/index.xml,v
retrieving revision 1.22
retrieving revision 1.23
diff -u -r1.22 -r1.23
--- index.xml 26 Jun 2002 00:59:49 -0000 1.22
+++ index.xml 13 Jul 2002 03:17:49 -0000 1.23
@@ -106,7 +106,8 @@
<li><a href="boss.html">12. Help! My boss wants me to load test our web
app!</a></li>
<li><a href="component_reference.html">13. Component Reference</a></li>
- <li><a href="glossary.html">14. Glossary</a></li>
+ <li><a href="functions.html">14. Functions</a></li>
+ <li><a href="glossary.html">15. Glossary</a></li>
</ul>
</section>
1.1 jakarta-jmeter/xdocs/usermanual/functions.xml
Index: functions.xml
===================================================================
<?xml version="1.0"?>
<document>
<properties>
<title>User's Manual: Introduction</title>
</properties>
<body>
<section name="14. Functions" anchor="functions">
<p>
JMeter functions are special values that can populate fields of any Sampler or other
configuration
element in a test tree. A function looks like this:</p>
<p><code>${__functionName(var1,var2,var3)}</code></p>
<p>Where "__functionName" matches the name of an existing built-in or user-defined
function.<br/>
Parentheses surround the parameters sent to the function. The actual parameters
vary from function
to function. Functions that require no parameters can leave off the parentheses.
The function itself
is wrapped in ${}.</p>
<subsection name="14.1 What can functions do" anchor="what_can_do">
<p>There are two kinds of functions: user-defined static values, and built-in
functions.<br/>
User-defined static values allows the user to define variables to be replaced with
their static value when
a test tree is compiled and submitted to be run. This replacement happens once at
the beginning of the test
run. This could be used to replace the DOMAIN field of all HTTP requests, for
example - making it a simple
matter to change a test to target a different server with the same test.
</p>
<p>This type of replacement is possible without functions, but was less convenient
and less intuitive.
It required users to create default config elements that would fill in blank values
of Samplers. User-defined
functions allows one to replace only part of any given value, not just filling in
blank values.</p>
<p>
With built-in functions users can compute new values at run-time based on previous
response data, which
thread the function is in, the time, and many other sources. These values are
generated fresh for every
request throughout the course of the test. </p>
</subsection>
<subsection name="14.2 Where can functions be used?" anchor="where">
<p>A user-defined function can be written into any field of any test component.
Some fields do not allow random strings
because they are expecting numbers, and thus will not accept a function. However,
most fields will allow
functions.</p>
<p>Built-in functions can be written into any field of non-controller test
components. This includes
Samplers, Timers, Listeners, Modifiers, Assertions, and Config Elements.</p>
</subsection>
<subsection name="14.3 Writing the function string" anchor="how">
<p>User-defined functions take the form: <code>${varName}</code>. In the TestPlan
tree element, a two-column table
of user-defined values is kept, matching up variable names with static values.
Referencing the
variable in a test element is done by bracketing the variable name with '${' and
'}'.</p>
<p>Built-in functions are written in the same manner, but by convention, the names
of built-in
parameters begin with "__" to avoid conflict with user value names<sup>*</sup>.
Some functions take arguments to
configure them, and these go in parentheses, comma-delimited. If the function takes
no arguments, the parentheses can
be left out. A further complication for argument values that themselves contain
commas is that the value
should be encoded the way HTTP parameters are encoded. JMeter provides a tool to
help you construct
function calls for various built-in functions, which you can then copy-paste. If
your argument values
do not contain commas, encoding is not required.</p>
<note><sup>*</sup>If you define a user-defined static variable with the same name as
a built-in function, your static
variable will override the built-in function.</note>
</subsection>
</section>
</body>
</document>
--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>