Other Samplers
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. |
The reference material consulted while preparing these pages is listed in the section bibliography.
This page was written against Apache JMeter 5.6.3, the latest release on 2026-10-14. It runs on Java 8 and later, and
Java 17 or later is recommended. JMeter 6.0 is not released: the differences noted here are planned per
xdocs/changes.xml on the master branch, which requires Java 17 or later (Java 21 recommended). The library versions
quoted for 5.6.3 come from its build (src/bom-thirdparty): Apache Commons Net 3.10.0 for FTP, JUnit 4.13.2 for the
JUnit Request, Neo4j Java driver 4.4.13 for Bolt and mongo-java-driver 2.14.3 for the deprecated MongoDB elements.
No element on this page needs the JMeter Plugins Manager 2.0: all of them ship with JMeter itself. The books on the
market target JMeter 2.11 to 3.0; they are cited only for the MongoDB sampler, which they still present as a normal
element. Every field, default and rule below comes from the official component reference, the FTP, LDAP, extended LDAP
and access-log tutorials, the properties file and the change log. Where the documentation is silent and the behaviour
is taken from the 5.6.3 source code, the text says so.
Most of a JMeter plan is HTTP. Earlier pages cover the HTTP Request sampler, and the two pages just before this one cover JDBC, JMS, mail and TCP. What is left is a mixed set of samplers. Some measure a protocol of their own (FTP, LDAP, Bolt). Some let a plan run code JMeter does not know about (OS Process, Java Request, JUnit Request). One replays recorded traffic (Access Log Sampler). Two are tools for building and debugging plans rather than measuring anything (Debug Sampler, Flow Control Action). And one, MongoDB Script, is deprecated and planned for removal. Each section below follows the same order: what the sampler does and when to use it, every field, a minimal example, its cost on the load generator, and its pitfalls.
Sampler overview
All the samplers on this page are added from the same menu, Add → Sampler, on a Thread Group or a controller. They follow the normal execution order described in Test Plan Elements, Execution Order & Scoping: configuration elements, pre-processors and timers in scope run before them, and post-processors, assertions and listeners after them. The one exception is the Flow Control Action, which produces no sample result.
| Sampler | Companion element | When to use it | Load-test fit | Status |
|---|---|---|---|---|
FTP Request |
FTP Request Defaults |
Download ( |
Good; one connection and login per sample. |
Current. |
LDAP Request |
LDAP Request Defaults, Login Config Element |
Simple add, modify, search and delete against a directory, including built-in self-cleaning tests. |
Fair; each sample opens its own connection. |
Current. |
LDAP Extended Request |
LDAP Extended Request Defaults |
A realistic LDAP session: thread bind, search, compare, add, modify, rename, delete, thread unbind, or a single bind/unbind to check a password. |
Good; the bind is reused for the whole thread session. |
Current. |
OS Process Sampler |
None |
Run a command on the load generator: a seed script, a health check, a CLI client of the system under test. |
Poor; a new operating-system process per sample. |
Current. |
Java Request |
Java Request Defaults |
Drive any Java client library through your own |
Very good; plain Java code, one instance per thread. |
Current. |
JUnit Request |
None |
Reuse an existing JUnit 3 or JUnit 4 test method as a sampler. |
Good if the tests are thread-safe. |
Current; JUnit 4 is the newest supported API. |
Bolt Request |
Bolt Connection Configuration |
Run Cypher queries against Neo4j over the Bolt protocol. |
Good; pooled driver connections. |
Current; Neo4j driver 6.x planned for 6.0. |
Access Log Sampler |
None |
Replay the request lines of a web server access log as HTTP requests. |
Fair; marked "Beta Code", parses only the request line. |
Current. |
Debug Sampler |
None |
Show JMeter variables, JMeter properties and system properties while building a plan. |
None; disable it for load runs. |
Current. |
Flow Control Action |
A timer as child (optional) |
Pause, stop the thread or the test, or change loop flow, typically inside an If Controller. |
Very good; generates no sample. |
Current; called Test Action before 5.0. |
MongoDB Script |
MongoDB Source Config |
Functional checks or set-up scripts against MongoDB, through the long-deprecated |
Not suitable (global write lock). |
Deprecated since 3.0, hidden from the menu, removal planned in 6.0. |
Source: Samplers (Component Reference)
The same choice as a decision tree:
Two other samplers are close cousins of this list and are covered elsewhere: the JSR223 Sampler in Scripting with JSR223 & Groovy, and the JDBC, JMS, SMTP, Mail Reader and TCP samplers in the database and messaging pages of this section.
FTP Request
What it does and when to use it
The FTP Request sends one FTP "retrieve file" or "upload file" request per sample. For a download the file can be stored on disk (Local File), kept in the response data, or both. Use it when the system under test exposes FTP as a real interface: a nightly catalogue export a partner downloads, or an import folder a supplier uploads to. It speaks plain FTP only; the element has no option for FTPS or SFTP.
In the 5.6.3 source each sample creates a new Apache Commons Net FTPClient, connects, logs in, switches to passive
mode, transfers the file, logs out and disconnects. The component reference states that Latency is set to the time it
takes to login; the source takes the latency mark right after the connection is established, before the login. In
both readings, the elapsed time of the sample covers the whole connect, login, transfer and logout cycle, so an FTP
sample measures a complete session, not just the transfer.
Fields
| GUI field | Meaning | JMX property | Required |
|---|---|---|---|
Name |
Label shown in the tree and in results. |
|
No |
Server Name or IP |
Domain name or IP address of the FTP server. |
|
Yes |
Port |
Port to use; if it is greater than 0 that port is used, otherwise the default FTP port. |
|
No |
Remote File |
File to retrieve, or name of the destination file to upload. |
|
Yes |
Local File |
File to upload, or destination for downloads (defaults to the remote file name). |
|
Yes, if uploading (or Local File Contents) |
Local File Contents |
The contents to upload; overrides Local File. |
|
Yes, if uploading (or Local File) |
get(RETR) / put(STOR) |
Whether to retrieve or upload a file. |
|
Yes |
Use Binary mode? |
Binary transfer; the default is ASCII. |
|
Yes |
Save File in Response? |
Store the contents of the retrieved file in the response data. In ASCII mode they are visible in View Results Tree. |
|
Yes, if downloading |
Username |
FTP account user name. |
|
Usually |
Password |
FTP account password. It is stored in clear text in the test plan. |
|
Usually |
FTP Request Defaults (Add → Config Element → FTP Request Defaults) has the same server, port, file and mode fields and supplies them to every FTP Request in its scope that leaves them empty.
Example: download the Bookshelf catalogue export
The official tutorial builds 4 users that fetch two files twice: (4 users) × (2 requests) × (2 loops) = 16 FTP requests. The Bookshelf version below is the same shape, aimed at a local FTP server that publishes the nightly catalogue export:
-
Select the Test Plan, then Add → Threads (Users) → Thread Group. Name it
FTP Users, set Number of Threads to 4, Ramp-up period to 0 and Loop Count to 2. -
On
FTP Users, Add → Config Element → FTP Request Defaults. Set Server Name or IP to${__P(host,localhost)}. Leave every other field empty. -
Add → Sampler → FTP Request. Name it
catalogue.csv, set Remote File to/exports/catalogue.csv, choose get(RETR), tick Use Binary mode?, and fill Username and Password from properties. -
Add a second FTP Request named
covers.zipfor/exports/covers.zip, also in binary mode. -
Add → Listener → View Results in Table while checking the plan; remove it for the real run.
<ConfigTestElement guiclass="FtpConfigGui" testclass="ConfigTestElement" testname="FTP Request Defaults">
<stringProp name="FTPSampler.server">${__P(host,localhost)}</stringProp>
<stringProp name="FTPSampler.port"></stringProp>
<stringProp name="FTPSampler.filename"></stringProp>
<stringProp name="FTPSampler.localfilename"></stringProp>
<stringProp name="FTPSampler.inputdata"></stringProp>
<boolProp name="FTPSampler.binarymode">false</boolProp>
<boolProp name="FTPSampler.saveresponse">false</boolProp>
<boolProp name="FTPSampler.upload">false</boolProp>
</ConfigTestElement>
<hashTree/>
<FTPSampler guiclass="FtpTestSamplerGui" testclass="FTPSampler" testname="catalogue.csv">
<stringProp name="FTPSampler.server"></stringProp>
<stringProp name="FTPSampler.port"></stringProp>
<stringProp name="FTPSampler.filename">/exports/catalogue.csv</stringProp>
<stringProp name="FTPSampler.localfilename"></stringProp>
<stringProp name="FTPSampler.inputdata"></stringProp>
<boolProp name="FTPSampler.binarymode">true</boolProp>
<boolProp name="FTPSampler.saveresponse">false</boolProp>
<boolProp name="FTPSampler.upload">false</boolProp>
<stringProp name="ConfigTestElement.username">${__P(ftp_user,bookshelf)}</stringProp>
<stringProp name="ConfigTestElement.password">${__P(ftp_password,changeme)}</stringProp>
</FTPSampler>
<hashTree/>
Source: Building an FTP Test Plan
The response code of a successful transfer is 200 (JMeter’s generic OK), and a refused transfer carries the FTP reply
code and reply text (for example 550) as response code and message, so a Response Assertion on the code works as it
does for HTTP. A connection failure is reported as 501, Could not connect, and an exception as 000.
Cost and pitfalls
-
Local File for downloads. With Local File set, every thread writes to that same path on disk. Leave it empty and untick Save File in Response? so that the transfer is measured without disk writes or memory use; tick it only on a debug run.
-
Big files in the response. Save File in Response? keeps the whole file in memory for every sample. A 50 MB export downloaded by 4 threads holds 200 MB of heap at once.
-
Clear-text credentials. The password is saved in the
.jmx. Use${__P(ftp_password,changeme)}and pass the real value with-Jftp_password=...on the command line, never commit it. -
No connection reuse. Each sample pays the connection and login cost. If the real clients keep a session open for many transfers, the test is more pessimistic than production.
LDAP Request
What it does and when to use it
The LDAP Request sends one of four operations to an LDAP server: Add, Modify, Search or Delete. Each operation can run as an inbuilt test or a user defined test:
| Operation | Inbuilt test | User defined test |
|---|---|---|
Add |
Adds a predefined entry, measures the time, then deletes the entry. |
Adds the entry described in the table; the entry is not deleted afterwards. |
Modify |
Creates a predefined entry, modifies it, measures the time, then deletes it. |
Modifies the entry described in the table; the entry is not deleted. |
Search |
Creates the entry, searches for its attributes, measures the search, then deletes it. |
Searches with the given search filter in the given search base; the entries must already exist. |
Delete |
Creates a predefined entry, then deletes it and measures the time. |
Deletes the given entry, which must already exist. |
Inbuilt tests are self-cleaning, which makes them a quick way to check that a directory accepts writes under load. User defined tests are the ones that resemble real traffic. Use the LDAP Request for simple, independent operations. When the traffic is a session (bind once, then several operations), use the LDAP Extended Request instead.
Fields
| GUI field | Meaning | JMX property | Required |
|---|---|---|---|
Server Name or IP |
Domain name or IP address of the LDAP server. |
|
Yes |
Port |
Port to connect to; default 389. |
|
Yes |
root DN |
Base DN for the operations. |
|
Yes |
Username / Password |
LDAP user and password, usually supplied by a Login Config Element. The password is stored unencrypted. |
|
Usually |
Test Configuration (Inbuilt / User defined) |
Which kind of test to run. |
|
Yes |
Add / Modify / Search / Delete |
The operation. |
|
Yes |
Entry DN |
Context to create or modify; you must supply its attributes yourself (to add |
|
User defined Add or Modify |
Delete |
Context to delete. |
|
User defined Delete |
Search base |
Context or object to search. |
|
User defined Search |
Search filter |
Filter expression for the search; may not be null. |
|
User defined Search |
add test / modify test table |
Name and value pairs for the new or modified object. |
|
User defined Add or Modify |
LDAP Request Defaults (Add → Config Element → LDAP Request Defaults) supplies server, port and DN to every LDAP Request in scope; the Login Config Element (Add → Config Element → Login Config Element) supplies user and password.
Example: the four inbuilt tests
The official tutorial runs the four inbuilt tests with 4 users and 4 loops: (4 users) × (4 requests) × (4 loops) = 64
LDAP requests. Against a local directory for the Bookshelf users (dc=bookshelf,dc=local):
-
Add → Threads (Users) → Thread Group named
LDAP Users: 4 threads, Loop Count 4. -
On
LDAP Users, Add → Config Element → Login Config Element: Usernamecn=admin,dc=bookshelf,dc=local, Password${__P(ldap_password,changeme)}. -
Add → Config Element → LDAP Request Defaults: Servername
${__P(host,localhost)}, Port 389, DNdc=bookshelf,dc=local. -
Add four LDAP Request samplers named
Add,Search,ModifyandDelete, and select the Add Test, Search Test, Modify Test and Delete Test radio button on each (Test Configuration left at Inbuilt). JMeter runs them in tree order. -
Add → Assertions → Response Assertion on
LDAP Users: Text Response, Substring, patternsuccessful. At that position it applies to every LDAP Request. -
Add → Listener → View Results in Table while checking the plan.
<LDAPSampler guiclass="LdapTestSamplerGui" testclass="LDAPSampler" testname="Search">
<stringProp name="servername"></stringProp>
<stringProp name="port"></stringProp>
<stringProp name="rootdn"></stringProp>
<boolProp name="user_defined">false</boolProp>
<stringProp name="test">search</stringProp>
<stringProp name="base_entry_dn"></stringProp>
<elementProp name="arguments" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="ConfigTestElement.username"></stringProp>
<stringProp name="ConfigTestElement.password"></stringProp>
</LDAPSampler>
<hashTree/>
Source: Building an LDAP Test Plan
Cost and pitfalls
-
Inbuilt tests measure more than one operation’s setup. An inbuilt Search creates and deletes an entry around the measured search, so the directory sees three writes per sample even though only one search is timed.
-
User defined Add leaves data behind. A load test that adds 10,000 entries leaves 10,000 entries; pair it with a user defined Delete or a clean-up in a tearDown Thread Group.
-
One connection per sample. Each sample is independent; for session traffic the LDAP Extended Request is closer to reality.
-
Credentials in the plan. Like every JMeter password field, it is stored unencrypted; feed it from a property.
LDAP Extended Request
What it does and when to use it
The LDAP Extended Request is the full-featured LDAP sampler. It is harder to configure than the LDAP Request but much closer to a real LDAP session. Any LDAP request is part of a session, so a thread starts with a Thread bind, runs its operations on that connection, and ends with a Thread unbind. The available operations are:
| Operation | LDAP operation | Notes |
|---|---|---|
Thread bind |
|
Opens the thread’s session. With no password, or a wrong password, the session is anonymous; omitting the password does not fail the test, but a wrong one does. |
Thread unbind |
|
Ends the session. |
Single bind/unbind |
|
Opens a new session just to check a user and password, then closes it: an authentication check. It is really two operations that cannot be split. |
Rename entry |
|
Renames an entry, or moves an entry or a whole subtree elsewhere in the tree. |
Add test |
|
Adds any kind of object. |
Delete test |
|
Deletes an object. |
Search test |
|
Searches with scope, size and time limits. |
Modification test |
|
Adds, deletes or replaces attribute values; all modifications must succeed or none is applied. |
Compare |
|
Compares an attribute with a value, typically to check group membership (the user’s DN against |
Fields
Every operation has a Name. The others depend on the selected operation:
| Operation | GUI field | Meaning | JMX property |
|---|---|---|---|
Thread bind |
Servername |
Name or IP of the LDAP server (required). |
|
Thread bind |
Port |
Port; if omitted, 389. |
|
Thread bind |
DN |
Base object for every later operation; no operation can start above it. |
|
Thread bind / Single bind |
Username |
Full DN of the user to bind as. |
|
Thread bind / Single bind |
Password |
Password for that user; omitted means anonymous; stored unencrypted. |
|
Thread bind |
Connection timeout (in milliseconds) |
Aborts the connection when exceeded. |
|
Thread bind |
Use Secure LDAP Protocol |
Use |
|
Thread bind |
Trust All Certificates |
Trust every certificate; only used with the secure protocol. |
|
Rename entry |
Old entry name / New distinguished name |
Current and new DN, relative to the bind DN. |
|
Add test |
Entry DN / attribute table |
DN to add (relative) and its attributes; repeat an attribute for multiple values. |
|
Delete test |
Delete |
DN to delete, relative to the bind DN. |
|
Search test |
Search base |
Subtree to search, relative to the bind DN; empty means the bind DN. |
|
Search test |
Search Filter |
Filter in LDAP syntax (required). |
|
Search test |
Scope |
0 base object, 1 one level, 2 subtree (default 0 per the reference). |
|
Search test |
Size Limit |
Maximum number of results; 0 means no limit. Hitting it fails the sample with error code 4. |
|
Search test |
Time Limit |
Maximum CPU time in ms the server may spend; 0 means no limit. It says nothing about response time. |
|
Search test |
Attributes |
Attributes to return, separated by semicolons; empty returns all. |
|
Search test |
Return object |
Return the Java object attributes too (default false). |
|
Search test |
Dereference aliases |
Follow aliases (default false). |
|
Search test |
Parse the search results? |
Put the results in the response data; otherwise only a found/not-found marker. |
|
Modification test |
Entry name / attribute-value-opCode table |
DN to modify and the |
|
Compare |
Entry DN / Compare filter |
DN to compare and an |
|
The selected operation is stored in the test property (bind, unbind, sbind, rename, add, delete,
search, modify, compare). LDAP Extended Request Defaults (Add → Config Element → LDAP Extended Request
Defaults) can pre-fill any of these fields; a value entered in a sampler overrides the default. When a value that a
test needs is missing everywhere, the tutorial warns that the test fails in an unpredictable way.
Example: a Bookshelf directory session
The official tutorial adds the nine operations in order for 1 user and 1 loop: (1 user) × (9 requests) × (1 loop) = 9 LDAP requests. A realistic Bookshelf session keeps only the read path: bind as the service account, look the user up, check group membership and unbind.
-
Add → Threads (Users) → Thread Group named
LDAP Ext Users. -
Add → Sampler → LDAP Extended Request, named
1. Thread bind: select Thread bind, Servername${__P(host,localhost)}, Port 389, DNdc=bookshelf,dc=local, Usernamecn=reader,dc=bookshelf,dc=local, Password${__P(ldap_password,changeme)}. -
2. Search Test: select Search Test, Search baseou=users, Search Filter(uid=${username}), Scope subtree, Attributescn;mail. -
3. Compare Test: select Compare, Entry DNcn=librarians,ou=groups, Compare filtermember=uid=${username},ou=users,dc=bookshelf,dc=local. -
4. Thread unbind: select Thread unbind. -
Add → Listener → View Results Tree while checking: its response data shows the request and the answer in an XML-style format.
<LDAPExtSampler guiclass="LdapExtTestSamplerGui" testclass="LDAPExtSampler" testname="2. Search Test">
<stringProp name="test">search</stringProp>
<stringProp name="search">ou=users</stringProp>
<stringProp name="searchfilter">(uid=${username})</stringProp>
<stringProp name="scope">2</stringProp>
<stringProp name="countlimit"></stringProp>
<stringProp name="timelimit"></stringProp>
<stringProp name="attributes">cn;mail</stringProp>
<stringProp name="return_object">false</stringProp>
<stringProp name="deref_aliases">false</stringProp>
<stringProp name="parseflag">true</stringProp>
</LDAPExtSampler>
<hashTree/>
username comes from the users.csv CSV Data Set Config that the rest of the section uses (see
Parameterization & Test Data).
Cost and pitfalls
-
Special characters in DNs. Escape LDAP special characters with a backslash (
cn=smith\+jonesfor a DN with a plus sign). To put a backslash itself in a DN for an add or rename, the tutorial requires four backslashes. -
Relative names. Every DN after the thread bind is relative to the bind DN. Entering a full DN in a search base doubles the suffix and the search finds nothing.
-
Time Limit is not a timeout. It caps server CPU time only; a large result over a slow link can still take a long time. Use the connection timeout and a Duration Assertion for response-time limits.
-
Attributes. Requesting all attributes returns large ones such as
jpegPhoto; list only what the client really reads, or""to return none. -
Parse the search results? Putting the results in the response costs memory per sample; leave it off for load runs unless an assertion needs them.
-
Single bind/unbind for logins. It is the right element for "check this password" traffic, and it is two network operations, not one.
OS Process Sampler
What it does and when to use it
The OS Process Sampler executes a command on the load generator machine. Any command that can be run from the command line can be run, and the return code can be validated. Typical uses: a setUp Thread Group that seeds the Bookshelf database with a script, a health check before the load starts, or driving a command-line client of the system under test when nothing else can speak its protocol.
The sampler deliberately does no parsing or quoting. The command and each parameter are passed as given, so the
settings are not portable between operating systems, and shell built-ins (Windows DIR, the POSIX shell’s cd) must
be passed to their command interpreter: Command CMD, Param 1 /C, Param 2 DIR, Param 3 the folder.
Fields
| GUI field | Meaning | JMX property | Required |
|---|---|---|---|
Command |
Program to execute. |
|
Yes |
Working directory |
Directory to run in; defaults to the |
|
No |
Command Parameters |
Parameters passed to the program, one per row. |
|
No |
Environment Parameters |
Key/value pairs added to the environment. |
|
No |
Standard input (stdin) |
File to read standard input from. |
|
No |
Standard output (stdout) |
File to write standard output to; if omitted it is captured as response data. |
|
No |
Standard error (stderr) |
File to write standard error to; if omitted it is captured as response data. |
|
No |
Check Return Code |
Compare the return code with the expected one. |
|
No |
Expected Return Code |
Expected code; do not use 500, which JMeter uses as an error indicator. |
|
If checking |
Timeout |
Milliseconds; 0 (default) means none. On expiry JMeter tries to kill the process. |
|
No |
Example: wait for the Bookshelf API before the test
In a setUp Thread Group (1 thread, 1 loop), Add → Sampler → OS Process Sampler: Command curl, parameters
--silent, --fail, --retry, 10, --retry-connrefused, and the URL; Check Return Code ticked with expected code
0; Timeout 60000. If the API is still down after the retries, curl returns a non-zero code, the sample fails, and the
Thread Group’s Action to be taken after a Sampler error can stop the test before the load starts.
<SystemSampler guiclass="SystemSamplerGui" testclass="SystemSampler" testname="Wait for Bookshelf API">
<boolProp name="SystemSampler.checkReturnCode">true</boolProp>
<stringProp name="SystemSampler.expectedReturnCode">0</stringProp>
<stringProp name="SystemSampler.command">curl</stringProp>
<elementProp name="SystemSampler.arguments" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments">
<collectionProp name="Arguments.arguments">
<elementProp name="" elementType="Argument">
<stringProp name="Argument.name"></stringProp>
<stringProp name="Argument.value">--silent</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="" elementType="Argument">
<stringProp name="Argument.name"></stringProp>
<stringProp name="Argument.value">--fail</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="" elementType="Argument">
<stringProp name="Argument.name"></stringProp>
<stringProp name="Argument.value">--retry</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="" elementType="Argument">
<stringProp name="Argument.name"></stringProp>
<stringProp name="Argument.value">10</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="" elementType="Argument">
<stringProp name="Argument.name"></stringProp>
<stringProp name="Argument.value">--retry-connrefused</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="" elementType="Argument">
<stringProp name="Argument.name"></stringProp>
<stringProp name="Argument.value">http://${__P(host,localhost)}:${__P(port,8080)}/api/books?query=health</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
</collectionProp>
</elementProp>
<elementProp name="SystemSampler.environment" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="SystemSampler.directory"></stringProp>
<longProp name="SystemSampler.timeout">60000</longProp>
</SystemSampler>
<hashTree/>
The curl options belong to curl itself, not to JMeter. The response code of the sample is the process’s return code;
with Check Return Code the response message is OK or Unexpected return code. Expected [0]. Actual [n]. If the
process cannot be started or is interrupted, the 5.6.3 source sets response code 500, which is why the documentation
reserves that value.
Cost and pitfalls
-
A process per sample. Starting an operating-system process costs far more than an HTTP request: memory for the new process, a fork, and the program’s own start-up. Keep the sampler in setUp and tearDown Thread Groups or in low-rate paths; never put it in the main loop of 50 threads.
-
It measures the command, including its start-up. Timing
curlwith this sampler measures curl’s start-up as much as the server; the HTTP Request sampler is the right tool for HTTP. -
Security. The command runs with the rights of the JMeter user on every load generator, including remote servers in distributed tests. Never build a command from response data.
-
Portability. A plan that calls
CMD /Cdoes not run on Linux CI agents and vice versa; keep OS-specific steps in a separate Test Fragment.
Java Request
What it does and when to use it
The Java Request controls a Java class that implements org.apache.jmeter.protocol.java.sampler.JavaSamplerClient.
By writing such a class you can put any Java client library (a proprietary protocol, a vendor SDK, a cache client)
under load and still let JMeter supply threads, parameters and result collection. The Classname drop-down lists every
implementation JMeter finds; two examples ship with it, JavaTest and SleepTest. JavaTest lets you set almost
every field of the result, which is handy for checking assertions and listeners without a server.
The life cycle comes from the interface’s Javadoc. JMeter creates one instance of the class per thread. When the test
starts it calls setupTest on each thread’s instance, then runTest once per iteration, and finally teardownTest.
Parameters are read through a JavaSamplerContext, and getDefaultParameters declares the parameter names and default
values the GUI shows. Extend AbstractJavaSamplerClient rather than implementing the interface directly: it provides
default implementations, and JMeter only calls teardownTest when a subclass overrides it, which reduces memory use.
Fields
| GUI field | Meaning | JMX property | Required |
|---|---|---|---|
Name |
Label shown in the tree. |
|
No |
Classname |
The |
|
Yes |
Send Parameters with Request |
Arguments passed to the class, all as strings; the rows come from |
|
No |
The parameters of the bundled examples:
| Parameter | Applies to | Meaning |
|---|---|---|
|
SleepTest, JavaTest |
How long to sleep, in ms. |
|
SleepTest, JavaTest |
Randomness added: total sleep = |
|
JavaTest |
Overrides the sample label. |
|
JavaTest |
Set the result’s response code and message. |
|
JavaTest |
|
|
JavaTest |
Set the request and response data of the result. |
Java Request Defaults (Add → Config Element → Java Request Defaults) sets default values for Java Requests in scope.
Example: a custom client for the Bookshelf search
The class below measures GET /api/books?query= with the JDK’s own HTTP client, standing in for any Java client
library. It reads its parameters once in setupTest, times only the call in runTest, and reports the HTTP status:
package com.example.bookshelf.jmeter;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient;
import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
import org.apache.jmeter.samplers.SampleResult;
public class BookSearchClient extends AbstractJavaSamplerClient {
private HttpClient client;
private String baseUrl;
@Override
public Arguments getDefaultParameters() {
Arguments args = new Arguments();
args.addArgument("baseUrl", "http://${__P(host,localhost)}:${__P(port,8080)}");
args.addArgument("term", "${term}");
args.addArgument("timeoutMs", "5000");
return args;
}
@Override
public void setupTest(JavaSamplerContext context) {
baseUrl = context.getParameter("baseUrl");
client = HttpClient.newBuilder()
.connectTimeout(Duration.ofMillis(context.getLongParameter("timeoutMs", 5000)))
.build();
}
@Override
public SampleResult runTest(JavaSamplerContext context) {
String term = context.getParameter("term", "java");
SampleResult result = new SampleResult();
result.setSampleLabel("Java search");
result.setSamplerData("GET /api/books?query=" + term);
HttpRequest request = HttpRequest.newBuilder(URI.create(
baseUrl + "/api/books?query=" + URLEncoder.encode(term, StandardCharsets.UTF_8))).GET().build();
result.sampleStart();
try {
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
result.sampleEnd();
result.setResponseCode(String.valueOf(response.statusCode()));
result.setResponseData(response.body(), StandardCharsets.UTF_8.name());
result.setSuccessful(response.statusCode() == 200);
} catch (Exception e) {
result.sampleEnd();
result.setResponseCode("500");
result.setResponseMessage(e.toString());
result.setSuccessful(false);
}
return result;
}
}
Compile it against ApacheJMeter_core and ApacheJMeter_java 5.6.3 (both on Maven Central under org.apache.jmeter)
with Java 11 or later (for java.net.http), package it as a jar and copy the jar to lib/ext. The default parameter
values are expressions; the Java Request evaluates them per sample like any other field, so term follows the CSV
data. The sampler block in the plan then looks like this:
<JavaSampler guiclass="JavaTestSamplerGui" testclass="JavaSampler" testname="Java search">
<elementProp name="arguments" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments">
<collectionProp name="Arguments.arguments">
<elementProp name="baseUrl" elementType="Argument">
<stringProp name="Argument.name">baseUrl</stringProp>
<stringProp name="Argument.value">http://${__P(host,localhost)}:${__P(port,8080)}</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="term" elementType="Argument">
<stringProp name="Argument.name">term</stringProp>
<stringProp name="Argument.value">${term}</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="timeoutMs" elementType="Argument">
<stringProp name="Argument.name">timeoutMs</stringProp>
<stringProp name="Argument.value">5000</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
</collectionProp>
</elementProp>
<stringProp name="classname">com.example.bookshelf.jmeter.BookSearchClient</stringProp>
</JavaSampler>
<hashTree/>
How the class is found. JMeter 5.6 started loading plugins through Java’s ServiceLoader instead of classpath
scanning (PR 5885). In 5.6.3 the Java Request still does both: it loads JavaSamplerClient services and also scans the
jars on the search path, and the source marks the scanning as a transition step towards ServiceLoader-only lookup. A
jar built today should therefore also carry a service file, so it keeps working when the scanning goes:
src/main/resources/META-INF/services/org.apache.jmeter.protocol.java.sampler.JavaSamplerClient
containing the single line com.example.bookshelf.jmeter.BookSearchClient.
Worked numbers. With the canonical load profile (50 threads, 60 s ramp-up) and the section’s 3 s think time, a Java Request whose call takes 0.2 s cycles every 3.2 s per thread: 50 / 3.2 ≈ 15.6 samples per second at full load, exactly like the HTTP version of the same step. The Java Request adds no overhead of its own beyond the class’s code.
Cost and pitfalls
-
State in fields is per thread. Each thread has its own instance, so fields set in
setupTestare safe. Static fields are shared by all threads and need thread-safe types. -
Time only the call. Put parameter parsing and client creation in
setupTest; whatever happens betweensampleStart()andsampleEnd()is what the reports show. -
Classname changes lose parameters. The GUI warns that changing the class of an existing Java Request may drop the parameters of the original plan.
-
Class not found. After copying the jar, restart JMeter; the GUI shows Classname not found in classpath when the class is missing.
-
Reuse versus a plugin. A Java Request has no GUI of its own beyond the parameter table. When a team needs a reusable element with fields, the page on extending JMeter later in this section covers writing a full sampler.
JUnit Request
What it does and when to use it
The JUnit Request runs an existing JUnit test method as a sampler, so a suite of functional tests can be put under load
without rewriting it. It supports the standard JUnit 3 convention (classes extending TestCase) and, with Search for
JUnit 4 annotations ticked, JUnit 4 annotations. The documentation does not mention JUnit 5 (Jupiter), and 5.6.3
bundles JUnit 4.13.2, so tests written for JUnit 5 only must be adapted or run through a Java Request instead.
Key differences from a normal JUnit runner:
-
JMeter creates one instance of the class per sampler and reuses it, unless Create a new instance per sample is ticked.
-
It measures only the test method:
setUpandtearDown(or@Beforeand@After) run but are not timed. -
oneTimeSetUpandoneTimeTearDownare supported as methods, and@BeforeClassand@AfterClassare treated as test methods so they can be run on their own, for example in a setUp Thread Group. -
It looks for a constructor taking a
Stringfirst, then an empty constructor. -
Unexpected exceptions are reported as errors.
-
JUnit test jars go in
lib/junit, notlib; theuser.classpathproperty can point elsewhere.
The recognised JUnit 4 annotations are @Test (with its expected and timeout attributes), @Before, @After,
@BeforeClass and @AfterClass.
Fields
| GUI field | Meaning | JMX property |
|---|---|---|
Search for JUnit 4 annotations |
Look for |
|
Package Filter |
Comma-separated list of packages to show in the class list. |
|
Class name |
Fully qualified test class (required). |
|
Constructor String |
String passed to the string constructor; when set, that constructor is used. |
|
Test Method |
The method to run (required). |
|
Success Message / Success Code |
Message and unique code for success (defaults Test successful, |
|
Failure Message / Failure Code |
Message and unique code for failure (defaults Test failed, |
|
Error Message / Error Code |
Message and code for errors (defaults An unexpected error occurred, |
|
Do not call setUp and tearDown |
Skip |
|
Append assertion errors |
Add assertion errors to the response message. |
|
Append runtime exceptions |
Add runtime exceptions to the response message (only if the previous box is unticked). |
|
Create a new instance per sample |
New test-class instance for each sample (default false). |
|
Example: reuse a Bookshelf smoke test
package com.example.bookshelf.smoke;
import static org.junit.Assert.assertEquals;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import org.junit.Before;
import org.junit.Test;
public class BookSearchSmokeTest {
private HttpClient client;
private String baseUrl;
@Before
public void setUp() {
client = HttpClient.newHttpClient();
baseUrl = System.getProperty("bookshelf.url", "http://localhost:8080");
}
@Test(timeout = 2000)
public void searchReturnsOk() throws Exception {
HttpResponse<String> response = client.send(
HttpRequest.newBuilder(URI.create(baseUrl + "/api/books?query=java")).GET().build(),
HttpResponse.BodyHandlers.ofString());
assertEquals(200, response.statusCode());
}
}
Package the compiled test classes as a jar, copy it to lib/junit, then Add → Sampler → JUnit Request: tick Search
for JUnit 4 annotations, set Package Filter to com.example.bookshelf, pick
com.example.bookshelf.smoke.BookSearchSmokeTest and the method searchReturnsOk. The setUp is public, as the
documentation requires, and keeps no static state. Pass the URL as a system property with -Dbookshelf.url=... when
JMeter starts.
<JUnitSampler guiclass="JUnitTestSamplerGui" testclass="JUnitSampler" testname="JUnit search smoke">
<stringProp name="junitSampler.classname">com.example.bookshelf.smoke.BookSearchSmokeTest</stringProp>
<stringProp name="junitsampler.constructorstring"></stringProp>
<stringProp name="junitsampler.method">searchReturnsOk</stringProp>
<stringProp name="junitsampler.pkg.filter">com.example.bookshelf</stringProp>
<stringProp name="junitsampler.success">Test successful</stringProp>
<stringProp name="junitsampler.success.code">1000</stringProp>
<stringProp name="junitsampler.failure">Test failed</stringProp>
<stringProp name="junitsampler.failure.code">0001</stringProp>
<stringProp name="junitsampler.error">An unexpected error occurred</stringProp>
<stringProp name="junitsampler.error.code">9999</stringProp>
<stringProp name="junitsampler.exec.setup">false</stringProp>
<stringProp name="junitsampler.append.error">true</stringProp>
<stringProp name="junitsampler.append.exception">false</stringProp>
<boolProp name="junitsampler.junit4">true</boolProp>
<boolProp name="junitsampler.createinstancepersample">false</boolProp>
</JUnitSampler>
<hashTree/>
Cost and pitfalls
The documentation’s own guidelines for tests that run well under JMeter:
-
Make
setUpandtearDownpublic and thread-safe; avoid static members. -
Keep each test method a discrete unit of work, not a long sequence of actions.
-
Do not make test methods depend on each other: JMeter can run them in any order.
-
Read configurable values from the jar rather than from files that differ per machine.
-
Because one instance is reused per sampler, put expensive initialisation in
oneTimeSetUp. -
Define unique success and failure codes and use them consistently, so results can be filtered.
The sampler itself is cheap. The cost is the test code: a test that creates a new HTTP client in setUp creates one per
sample, which is slower than production clients that reuse connections.
Bolt Request
What it does and when to use it
The Bolt Request runs Cypher queries against Neo4j over the Bolt protocol. It was added in JMeter 5.2; 5.5 added the database, access-mode and transaction-timeout options and the pool-size setting. Each request takes a connection from the pool of a Bolt Connection Configuration and returns it when the sample completes. The measured time is the full query execution: running the Cypher statement and consuming the results the database sends back.
For Neo4j itself (the property graph model, Cypher, drivers, transactions and clustering), see the Neo4j Reference, in particular Cypher fundamentals and Transactions and drivers. This section adds only what JMeter needs.
Fields
Bolt Connection Configuration (Add → Config Element → Bolt Connection Configuration):
| GUI field | Meaning | JMX property | Default |
|---|---|---|---|
Bolt URI |
Database URI: |
|
|
Username |
User account. |
|
|
Password |
User credentials. |
|
empty |
Connection Pool Max Size |
Size of the driver’s Bolt connection pool. Raise it with many threads so they do not wait for a connection. |
|
100 |
Bolt Request (Add → Sampler → Bolt Request):
| GUI field | Meaning | JMX property |
|---|---|---|
Cypher Statement |
The query to execute (required). |
|
Params |
Parameter values, JSON formatted. |
|
Record Query Results |
Add the result data to the response (default false). Memory overhead: debug only. |
|
Access Mode |
|
|
Database |
Database to query. Required for Neo4j 4.0 and later unless querying the default database; must be empty for 3.5. |
|
Transaction timeout |
Timeout for the transaction. The documentation gives no unit; the GUI tooltip and the 5.6.3 source use seconds, and 0 means no timeout. |
|
The documentation strongly advises query parameters, which let the database cache and reuse execution plans.
Concatenating ${bookId} into the Cypher text produces a new query text per value and defeats that cache.
Example: Bookshelf recommendations
Suppose Bookshelf keeps "readers also borrowed" links in a local Neo4j as (:Book)-[:ALSO_BORROWED]->(:Book). The
request below reads five recommendations for the book the user is viewing:
<BoltConnectionElement guiclass="TestBeanGUI" testclass="BoltConnectionElement" testname="Bolt Connection Configuration">
<stringProp name="boltUri">bolt://${__P(host,localhost)}:7687</stringProp>
<stringProp name="username">neo4j</stringProp>
<stringProp name="password">${__P(neo4j_password,changeme)}</stringProp>
<intProp name="maxConnectionPoolSize">100</intProp>
</BoltConnectionElement>
<hashTree/>
<BoltSampler guiclass="TestBeanGUI" testclass="BoltSampler" testname="Recommendations">
<stringProp name="cypher">MATCH (b:Book {id: $bookId})-[:ALSO_BORROWED]->(r:Book) RETURN r.title LIMIT 5</stringProp>
<stringProp name="params">{"bookId": "${bookId}"}</stringProp>
<boolProp name="recordQueryResults">false</boolProp>
<stringProp name="accessMode">READ</stringProp>
<stringProp name="database">neo4j</stringProp>
<intProp name="txTimeout">5</intProp>
</BoltSampler>
<hashTree/>
$bookId is a Cypher parameter resolved by Neo4j; ${bookId} is a JMeter variable resolved by JMeter inside the
JSON of Params. The two are not the same thing, and only the JMeter one is substituted before the query is sent.
Worked numbers for the pool. The 5.6.3 source creates one driver, with the configured pool, when the test starts, and every Bolt Request borrows from it. With 150 threads and the default pool of 100, at most 100 queries can be in flight, and up to 50 threads wait for a connection; that wait is inside the measured time. If a query takes 20 ms and think time is 3 s, each thread holds a connection less than 1 % of the time and 100 connections are plenty; the pool only matters for short think times or long queries. Size it as at least the number of threads that can run a Bolt Request at the same moment.
Cost and pitfalls
-
Record Query Results. It iterates the whole result set into the response; leave it off for load runs.
-
Access mode on a cluster. A read query sent as
WRITEall goes to the leader and overloads it; mark reads asREAD. -
Database on Neo4j 3.5. A database name makes the request fail there; leave the field empty.
-
Driver version. JMeter 5.6.3 bundles Neo4j Java driver 4.4.13;
changes.xmlon master plans the Neo4j Java driver 6.x for 6.0. Check the Neo4j driver compatibility notes for the server version under test.
Access Log Sampler
What it does and when to use it
The Access Log Sampler reads a web server access log and turns each entry into an HTTP request, so a test can replay real traffic instead of a guessed mix. The access-log tutorial lists its benefits: real traffic data, a record of how usage changes over time, and session information. It also lists the cases where access logs are inappropriate:
-
security-sensitive applications where the data is encrypted;
-
applications that do not allow fine-grained control of which request parameters are written to the log;
-
applications that need correlation between requests (a log cannot replay a JWT obtained at login);
-
web servers that cannot append the POST data to the log;
-
servers hosting several applications without a separate log per application.
A log that contains POST data can contain passwords in plain text, so the tutorial also suggests custom logging that keeps sensitive data out of the log.
The sampler understands the common log format:
127.0.0.1 - - [21/Oct/2003:05:37:21 -0500] "GET /index.jsp?%2Findex.jsp= HTTP/1.1" 200 8343
The parser only looks at the quoted text containing an HTTP method (GET, PUT, POST, DELETE and so on). Everything else, including the response code, is ignored. Internally the sampler creates an HTTP sampler through a generator, sets its server, port and image parsing, asks the parser for one entry and calls the HTTP sampler. So each sample replays exactly one log line. The component reference still labels the element (Beta Code).
Fields
| GUI field | Meaning | JMX property | Required |
|---|---|---|---|
Server |
Domain name or IP address of the web server. |
|
Yes |
Protocol |
Scheme, |
|
No (default |
Port |
Port the web server listens on. |
|
No (default 80) |
Parse Images |
Download images and resources contained in each page. |
|
No (default false) |
Parser |
Class that parses the log (default |
|
Yes (default provided) |
Filter (Optional) |
Class that filters out lines. |
|
No |
Log File |
Location of the access log. |
|
Yes |
The parsers and filters differ in how threads share the log:
| Class | Behaviour |
|---|---|
|
Each thread processes the whole log independently. |
|
Threads share the file: each thread gets the next entry. |
|
Filters nothing; it makes sure the cookies of one client IP are processed by one thread at a time. A second thread that wants an entry from the same IP waits until the first has finished. |
|
Filters entries by file name and regex and can replace extensions, but it cannot be configured from the GUI, so it cannot really be used. |
Example: replay a Bookshelf access log
-
Add → Threads (Users) → Thread Group, then Add → Sampler → Access Log Sampler.
-
Add → Listener → Aggregate Report on the Thread Group, with
results.jtlas file name (in CLI mode use-linstead). -
In the Access Log Sampler set Server
${__P(host,localhost)}, Port${__P(port,8080)}, leave Parse Images off for an API, and point Log File at the access log. -
Start the test (Run → Start, or Ctrl + R).
<AccessLogSampler guiclass="TestBeanGUI" testclass="AccessLogSampler" testname="Replay access log">
<elementProp name="HTTPsampler.Arguments" elementType="Arguments">
<collectionProp name="Arguments.arguments"/>
</elementProp>
<stringProp name="domain">${__P(host,localhost)}</stringProp>
<stringProp name="portString">${__P(port,8080)}</stringProp>
<boolProp name="imageParsing">false</boolProp>
<stringProp name="logFile">logs/bookshelf-access.log</stringProp>
<stringProp name="parserClassName">org.apache.jmeter.protocol.http.util.accesslog.SharedTCLogParser</stringProp>
<stringProp name="filterClassName"></stringProp>
</AccessLogSampler>
<hashTree/>
Source: Access log sampler Step-by-step
Worked numbers. Take a one-hour Bookshelf log of 36,000 lines and a Thread Group of 10 threads, each with an
iteration count large enough to reach the end of the log. With TCLogParser every thread replays the whole log, so the
server receives 10 × 36,000 = 360,000 requests: ten copies of the same hour. With SharedTCLogParser the threads take
turns, so the log is replayed once, 36,000 requests in total, at whatever speed 10 threads without think time can
reach. Neither parser reproduces the timestamps of the log; add a timer if the original pacing matters. The behaviour at
the end of the file is not described in the documentation, so set the iteration count from the line count rather than
relying on it.
Cost and pitfalls
-
Only GET-style replay is reliable. The request line is all that is parsed; bodies are not in the common log format.
-
No correlation. Requests that need a token, a CSRF value or an ID created earlier fail on replay. Use access logs to derive the mix of a workload model (see Performance Testing Fundamentals) and build the journey with HTTP Requests.
-
Every line, including static files. The log contains every image, CSS and JavaScript request the server saw; filter the file beforehand if only API calls matter.
-
Privacy. Production logs contain client IPs and possibly personal data in query strings; anonymise them before they reach a load generator.
-
Extending it. Custom formats need a class implementing
org.apache.jmeter.protocol.http.util.accesslog.LogParser(setGenerator(Generator),parse(int)) and possibly aGenerator;TCLogParserandStandardGeneratorare the reference implementations.
Debug Sampler
What it does and when to use it
The Debug Sampler generates a sample whose response data lists the values of all JMeter variables, JMeter properties
and system properties, each section sorted by name. It is the quickest way to see what a CSV Data Set, an extractor or
a __P call really produced while a plan is being built: put it after the step under suspicion and look at the
Response Data pane of View Results Tree.
Fields
| GUI field | Meaning | JMX property | Default |
|---|---|---|---|
JMeter Properties |
Include JMeter properties. |
|
false |
JMeter Variables |
Include JMeter variables. |
|
true |
System Properties |
Include system properties. |
|
false |
Example: check the Bookshelf login correlation
After the login request of bookshelf-load.jmx, Add → Sampler → Debug Sampler named DEBUG after login, with only
JMeter Variables ticked:
<DebugSampler guiclass="TestBeanGUI" testclass="DebugSampler" testname="DEBUG after login">
<boolProp name="displayJMeterProperties">false</boolProp>
<boolProp name="displayJMeterVariables">true</boolProp>
<boolProp name="displaySystemProperties">false</boolProp>
</DebugSampler>
<hashTree/>
Run one thread and one iteration; the response data reads like this (values shortened, placeholders only):
JMeterVariables:
JMeterThread.last_sample_ok=true
...
START.MS=...
...
password=placeholder
term=java
token=eyJhbGciOi...
username=reader01
If token is missing or holds the extractor’s default value, the problem is in the extractor, not in the next request.
The neighbouring Debug PostProcessor does the same as a sub-sample of a chosen sampler and can also show the sampler’s
properties; see Correlation & Extractors for the full debugging
workflow.
Cost and pitfalls
-
Disable it for load runs. Every Debug Sampler is a sample in the results, so it skews counts, throughput and the dashboard, and JMeter Properties or System Properties add several kilobytes of text per sample.
-
Secrets in results. Variables include tokens and passwords read from CSV files; a results file saved with response data will contain them.
-
Ignore it in transactions. A Debug Sampler inside a Transaction Controller adds its (tiny) time to the transaction.
Flow Control Action
What it does and when to use it
The Flow Control Action is a sampler intended for use inside a conditional controller. Rather than generate a sample,
it pauses, stops the selected target, or changes the loop flow. It was called Test Action before JMeter 5.0, and the
older name still appears in old plans and in the .jmx class name, TestAction. JMeter 5.0 also added the loop actions
Go to next iteration of Current Loop and Break Current Loop.
Typical uses:
-
stop a thread whose login failed, from inside an If Controller, so it does not send requests without a token;
-
add a pause inside a Transaction Controller without generating a sample, so think time can be part of a transaction when that is wanted;
-
carry a timer: set the duration to 0 and add a timer as a child for a variable pause;
-
carry a pre- or post-processor that must run once at a point of the flow without a sample of its own (the pattern used in Logic Controllers & Transactions).
Fields
| GUI field | Values | JMX property |
|---|---|---|
Name |
Label shown in the tree. |
|
Target |
Current Thread (0) or All Threads (2); ignored for Pause and the loop actions. |
|
Logical Action on Thread/Test |
Pause (1), Stop (0), Stop Now (2), Start Next Thread Loop (3), Go to next iteration of Current Loop (4), Break Current Loop (5). |
|
Duration (milliseconds) |
How long to pause; required for Pause, default 0. |
|
The component reference lists the actions as Pause, Stop, Stop Now and Go to next loop iteration; the 5.6.3 GUI shows the six radio buttons above, and the numbers in parentheses are the stored values from the 5.6.3 source.
Stop stops the thread or test after any samples in progress complete. Stop Now stops the test without waiting and
interrupts active samples. If some threads do not stop within 5 seconds, GUI mode shows a message, and CLI mode exits
JMeter. That limit is the jmeterengine.threadstop.wait property, in milliseconds (default 5000).
Example: stop the thread when login fails
<IfController guiclass="IfControllerPanel" testclass="IfController" testname="If login failed">
<stringProp name="IfController.condition">${__jexl3("${token}" == "TOKEN_NOT_FOUND")}</stringProp>
<boolProp name="IfController.evaluateAll">false</boolProp>
<boolProp name="IfController.useExpression">true</boolProp>
</IfController>
<hashTree>
<TestAction guiclass="TestActionGui" testclass="TestAction" testname="Stop this user">
<intProp name="ActionProcessor.action">0</intProp>
<intProp name="ActionProcessor.target">0</intProp>
<stringProp name="ActionProcessor.duration">0</stringProp>
</TestAction>
<hashTree/>
</hashTree>
TOKEN_NOT_FOUND is the default value given to the JSON Extractor for token in the login step (see
Correlation & Extractors); the If Controller and its Interpret
Condition as Variable Expression? option are covered in
Logic Controllers & Transactions. Only the threads whose
login failed stop; the others carry on, instead of the failed ones sending unauthenticated requests, each counted as an
error, for the rest of the run.
Cost and pitfalls
-
No sample means no assertion. Post-processors, assertions and listeners are skipped because the result is null; record the reason in a variable or a log line if it matters for analysis.
-
A fixed pause is not think time. The Pause duration is a fixed number of milliseconds; for think time with variation use timers (or a timer as child of a zero-duration Flow Control Action), and keep plain pauses for conditional waits.
-
Stop Now on All Threads. It interrupts samples in progress, so the last results of every thread are errors.
-
Old plans. A plan saved by JMeter 4 or earlier still says
TestAction; that is the same element.
MongoDB Script (deprecated)
Status
The MongoDB Script sampler and its MongoDB Source Config element were deprecated in JMeter 3.0 (Bugzilla 58772). Since
then they no longer appear in the menu: the default not_in_menu property in bin/jmeter.properties lists
org.apache.jmeter.protocol.mongodb.sampler.MongoScriptSampler and
org.apache.jmeter.protocol.mongodb.config.MongoSourceElement. The JMeter team advises not to use them. The
changes.xml on master plans their removal in 6.0 (PR 6573), together with the bundled mongo-java-driver (2.14.3 in
5.6.3): plans that use them will no longer load, and the stated replacement is a JSR223 Sampler with the MongoDB Java
driver of your choice.
The books still present this sampler as a normal element (Cookbook ch. 4; PTwJ ch. 7). Treat those recipes as history.
What it does
The sampler sends a script to MongoDB through com.mongodb.DB#eval, which takes a global write lock and so hurts the
database’s performance. The documentation itself says it is better avoided for load testing and is more suitable for
functional testing or test set-up in setUp and tearDown Thread Groups.
| GUI field | Meaning | JMX property | Required |
|---|---|---|---|
MongoDB Source |
Name of the JMeter variable the connection is bound to; must match the MongoDB Source of a MongoDB Source Config. |
|
Yes |
Database Name |
Database used by the script. |
|
Yes |
Username / Password |
Credentials. |
|
No |
Script |
Mongo script as it would be used in the MongoDB shell. |
|
Yes |
The MongoDB Source Config takes a Server Address List, the MongoDB Source variable name (unique across the plan), and driver options: Keep Trying, Maximum connections per host, Connection timeout, Maximum retry time, Maximum wait time (default 120,000 ms), Socket timeout, Socket keep alive, ThreadsAllowedToBlockForConnectionMultiplier (default 5) and the write-concern settings (Safe, Fsync, Wait for Journal, Wait for servers, Wait timeout, Continue on error). Each thread gets its own connection.
Migration: a JSR223 Sampler with a current driver
The replacement that changes.xml names is a JSR223 Sampler with a MongoDB Java driver you install yourself. Copy the
synchronous driver jars (mongodb-driver-sync, mongodb-driver-core and bson, all the same version) into lib,
restart JMeter, and share one MongoClient per test through a property, created once in a setUp Thread Group:
// setUp Thread Group, JSR223 Sampler "Create MongoClient" (Groovy, cache compiled script ticked)
import com.mongodb.client.MongoClients
def uri = 'mongodb://' + (props.get('host') ?: 'localhost') + ':27017'
props.put('mongoClient', MongoClients.create(uri))
SampleResult.setIgnore()
// main Thread Group, JSR223 Sampler "Find book" (Groovy, cache compiled script ticked)
import com.mongodb.client.model.Filters
def books = props.get('mongoClient').getDatabase('bookshelf').getCollection('books')
def doc = books.find(Filters.eq('_id', vars.get('bookId'))).first()
SampleResult.setResponseData((doc?.toJson() ?: 'null'), 'UTF-8')
SampleResult.setSuccessful(doc != null)
The scripts follow the rules of
Scripting with JSR223 & Groovy: no ${...} inside a
cached script (values come from vars and props), one shared client because the MongoDB driver manages its own
connection pool, and a MongoClient.close() in a tearDown Thread Group. The JSR223 Sampler times the whole script, so
keep it to the database call.
Changes from the books to 5.6 and 6.0
| Element | JMeter 2.x / 3.0 (books) | JMeter 5.6.3 | Planned for 6.0 (changes.xml on master) |
|---|---|---|---|
Flow Control Action |
Test Action, with Pause, Stop, Stop Now and Go to next loop iteration. |
Renamed in 5.0; Go to next iteration of Current Loop and Break Current Loop added in 5.0. |
No change listed. |
MongoDB Script, MongoDB Source Config |
Presented as normal elements (Cookbook ch. 4, PTwJ ch. 7); deprecated in 3.0. |
Deprecated, hidden by |
Removed with the driver; plans using them no longer load. |
Bolt Request |
Did not exist. |
Added in 5.2; database, access mode, transaction timeout and pool size added in 5.5; Neo4j Java driver 4.4.13. |
Neo4j Java driver 6.x. |
Java Request |
Classes found by classpath scanning. |
ServiceLoader plus legacy scanning (5.6, PR 5885). |
Requires Java 17 or later to run; no Java Request change listed. |
JUnit Request |
JUnit 3 and 4. |
JUnit 3 and 4, JUnit 4.13.2 bundled. |
No change listed. |
FTP, LDAP, LDAP Extended, OS Process, Access Log, Debug Sampler |
Same elements. |
Same elements and fields. |
No change listed; 6.0 updates bundled libraries such as Commons Net (3.13.0). |
Source: Changes history and changes.xml on master
References
-
FTP Request and FTP Request Defaults (Component Reference)
-
LDAP Request, LDAP Request Defaults and Login Config Element (Component Reference)
-
LDAP Extended Request and LDAP Extended Request Defaults (Component Reference)
-
Java Request and Java Request Defaults (Component Reference)
-
Bolt Request and Bolt Connection Configuration (Component Reference)
-
MongoDB Script (DEPRECATED) and MongoDB Source Config (DEPRECATED) (Component Reference)
-
JMeter Javadoc (
JavaSamplerClient,AbstractJavaSamplerClient,JavaSamplerContext,SampleResult) -
Changes history (MongoDB deprecation in 3.0, Test Action renamed in 5.0, Bolt in 5.2 and 5.5, ServiceLoader in 5.6)
-
Apache JMeter source (5.6.3 sampler classes and GUIs,
bin/jmeter.properties,bin/saveservice.properties,src/bom-thirdparty, andxdocs/changes.xmlon master for planned 6.0 changes) -
Bayo Erinle, JMeter Cookbook, Packt, 2014 (JMeter 2.11), ch. 4: the MongoDB sampler, used for context only.
-
Bayo Erinle, Performance Testing with JMeter, 2nd ed., Packt, 2015 (JMeter 2.12), ch. 7: the MongoDB sampler, used for context only.